我想为某个类创建完成处理程序,而不是触发类的主要代码并等待委托回调。 我已经阅读了苹果文档,他们似乎没有很好地解释如何直接实现这样的东西。
我想为某个类创建完成处理程序,而不是触发类的主要代码并等待委托回调。 我已经阅读了苹果文档,他们似乎没有很好地解释如何直接实现这样的东西。
如果是针对一个异步方法,你可以这样做
- (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
指向某个值,否则如果尝试执行它,程序会崩溃。
我经常使用块来作为完成处理程序的方式之一,当一个视图控制器已经完成并希望从导航栈中弹出时。
@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];
};
}
您需要像对待变量一样处理完成块。该方法将接受块作为其参数的一部分,然后将其存储以备后用。
- (void)myMethodWithCompletionHandler:(void (^)(id, NSError*))handler;
您可以为该块类型进行typedef以便更容易阅读:
typedef void (^CompletionBlock)(id, NSError*);
然后将您的块存储为实例变量:
在您的@interface中:CompletionBlock _block;
在myMethod..中:_block = [handler copy]
然后当您想要执行完成块时,只需像常规块一样调用它:
_block(myData, error);
copy
关键字将代码块复制到堆上(默认情况下,客户端传递给您的代码块存储在栈上)。 - yonelfunc doSomething(input: String, completion: (result: String) -> Void {
print(input)
completion(result: "we are done!")
}
调用函数:
doSomething("cool put string!") { (result) in
print(result)
}
Chris C的答案是正确的(对我非常有帮助),但有一个注意点:
在@interface
中放置声明CompletionBlock _block;
不是线程安全的。
如果存在多个线程(或调度队列)调用myMethod…
的可能性,请在myMethod…
中放置CompletionBlock _block = [handler copy];
。
感谢@Chris C。
dispatch_async
。 - Paul.sdispatch_async
的第二次调用。 - Paul.s