UIViewController如何等待其他类中执行的dispatch_async任务完成?
问题根源
当前现象是GCD异步API的正常表现:dispatch_async会将任务提交到队列后立刻返回,不会等待任务执行完成,因此你写在调用语句后的代码会立刻执行,不会等待异步任务结束。
可行解决方案
方案1:将后续逻辑移入回调Block(最推荐)
这是最符合异步编程规范的方案,不会阻塞任何线程,也不会出现死锁风险,直接把需要等待异步结束后执行的代码放到completionHandler回调中即可:
[dispatch_thread addNumber:5 withNumber:7 andCompletionHandler:^(int result) { NSLog(@"The dispatch from class finished ...%i",result); // 后续逻辑移到此处 NSLog(@"Continue after dispatch_async finished ..."); }];
方案2:使用dispatch_group异步监听任务完成
如果后续逻辑不能和回调内容耦合,可以用调度组监听任务完成状态,不会阻塞当前线程:
dispatch_group_t taskGroup = dispatch_group_create(); // 标记任务开始 dispatch_group_enter(taskGroup); [dispatch_thread addNumber:5 withNumber:7 andCompletionHandler:^(int result) { NSLog(@"The dispatch from class finished ...%i",result); // 标记任务结束 dispatch_group_leave(taskGroup); }]; // 监听所有任务完成,指定后续逻辑执行的队列 dispatch_group_notify(taskGroup, dispatch_get_main_queue(), ^{ NSLog(@"Continue after dispatch_async finished ..."); });
方案3:使用dispatch_semaphore实现同步等待
如果确实需要阻塞当前线程等待任务完成,可以用信号量实现,注意:禁止在主线程调用该方案,否则会出现死锁:你的completionHandler是回调到主线程执行的,主线程卡在等待步骤时,回调永远无法执行,导致程序卡住:
// 初始化信号量,初始值为0 dispatch_semaphore_t sem = dispatch_semaphore_create(0); [dispatch_thread addNumber:5 withNumber:7 andCompletionHandler:^(int result) { NSLog(@"The dispatch from class finished ...%i",result); // 发送信号,信号量+1 dispatch_semaphore_signal(sem); }]; // 等待信号量,信号量大于0时才会继续往下执行 dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); NSLog(@"Continue after dispatch_async finished ...");
方案4:自定义类新增同步执行接口
如果该工具类经常有同步等待的需求,可以新增同步调用的方法:
- 头文件新增声明:
@interface dispatch_thread : NSObject // 原有方法保留 +(void)addNumber:(int)number1 withNumber:(int)number2 andCompletionHandler:(void (^)(int result))completionHandler; // 新增同步方法声明 +(void)syncAddNumber:(int)number1 withNumber:(int)number2 andCompletionHandler:(void (^)(int result))completionHandler; @end
- 实现文件新增实现:
@implementation dispatch_thread // 原有方法实现保留 +(void)addNumber:(int)number1 withNumber:(int)number2 andCompletionHandler:(void (^)(int result))completionHandler{ // 原有实现不变 } // 新增同步方法实现 +(void)syncAddNumber:(int)number1 withNumber:(int)number2 andCompletionHandler:(void (^)(int result))completionHandler{ int result = number1 + number2; dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 改用dispatch_sync同步提交任务,会等待任务执行完成再返回 dispatch_sync(queue, ^{ int i=1000; while (i>0) { NSLog(@"doing something in class...%i",i); i--; } // 线程安全处理,避免死锁 if ([NSThread isMainThread]) { NSLog(@"callback in class..."); completionHandler(result); } else { dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"callback in class..."); completionHandler(result); }); } }); } @end
调用时直接使用同步方法即可,调用后的代码会自动等待任务完成后执行:
[dispatch_thread syncAddNumber:5 withNumber:7 andCompletionHandler:^(int result) { NSLog(@"The dispatch from class finished ...%i",result); }]; NSLog(@"Continue after dispatch_async finished ...");
内容的提问来源于stack exchange,提问作者stefanosn
相关产品推荐
相关产品推荐

