Я хочу создать обработчик завершения для определенного класса, вместо того, чтобы отключить основной код класса и ждать обратного вызова делегата. Я прочитал документацию Apple и, похоже, не очень хороший пример того, как напрямую реализовать что-то подобное.
Как создать собственный обработчик завершения как часть параметров метода
Ответ 1
Вам нужно обработать блок завершения так же, как переменную. Метод примет блок как часть его параметров, а затем сохранит его позже.
- (void)myMethodWithCompletionHandler:(void (^)(id, NSError*))handler;
Вы можете напечатать этот тип блока для упрощения чтения:
typedef void (^CompletionBlock)(id, NSError*);
И затем сохраните свой блок как переменную экземпляра:
В вашем @interface: CompletionBlock _block;
В myMethod.. _block = [handler copy]
Затем, когда вы хотите выполнить блок завершения, вы просто назовете его как обычный блок:
_block(myData, error);
Ответ 2
Если бы это был асинхронный метод, вы могли бы сделать это следующим образом:
- (void)asynchronousTaskWithCompletion:(void (^)(void))completion;
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Some long running task you want on another thread
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) {
completion();
}
});
});
}
это будет вызываться с помощью
[self asynchronousTaskWithCompletion:^{
NSLog(@"It finished");
}];
Следует отметить, что охранник должен удостовериться, что completion
указывает на что-то, иначе мы сбой, если попытаемся его выполнить.
Другой способ, которым я часто использую блоки для обработчиков завершения, - это когда обработчик viewController закончил и хочет, чтобы его выталкивали из стека навигации.
@interface MyViewController : UIViewController
@property (nonatomic, copy) void (^onCompletion)(void);
@end
@implementation MyViewController
- (IBAction)doneTapped;
{
if (self.onCompletion) {
self.onCompletion();
}
}
@end
Вы должны установить блок завершения при нажатии этого представления на стек
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;
{
MyViewController *myViewController = segue.destinationViewController;
myViewController.onCompletion = ^{
[self.navigationController popViewControllerAnimated:YES];
};
}
Ответ 3
Вот пример метода, который берет String и обработчик завершения как переменные. Обработчик завершения также может получить строку.
Swift 2.2 Синтаксис
Defintion:
func doSomething(input: String, completion: (result: String) -> Void {
print(input)
completion(result: "we are done!")
}
Вызов функции:
doSomething("cool put string!") { (result) in
print(result)
}
Ответ 4
Крис C ответ правильный (и был очень полезен для меня) с одной оговоркой:
Размещение объявления CompletionBlock _block;
в @interface
не является безопасным для потоков.
Поместите CompletionBlock _block = [handler copy];
в myMethod…
вместо этого, если есть вероятность, что myMethod…
будет вызван из нескольких потоков (или очередей отправки).
Спасибо @Chris C.