Objective-C中如何让带返回值的方法等待异步block执行完成后返回
你代码中存在的核心问题是createPDFFromEmail:completionHandler:的completionHandler是异步回调,原方法执行到return语句时,回调block还未触发,returnValue还没被赋值,最终返回的是未初始化的错误值。
有两种常用重构方案,分别适配不同的使用场景:
方案1:使用GCD信号量同步等待block执行(仅适合子线程调用场景)
通过信号量阻塞当前线程,直到block执行完成再继续执行return逻辑,代码如下:
- (long)someMethod { long returnValue; // 初始化计数为0的信号量 dispatch_semaphore_t sem = dispatch_semaphore_create(0); [MFPDFConverter createPDFFromEmail:emailToConvert completionHandler:^(long longObtainedFromBlock) { NSLog(@"Here we are"); returnValue = longObtainedFromBlock; // block执行完成,信号量计数+1 dispatch_semaphore_signal(sem); }]; // 阻塞当前线程,直到信号量计数≥1才继续执行,计数同时-1 dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); return returnValue; }
注意事项:
- 该方案会阻塞当前调用线程,如果在主线程调用会导致界面无响应卡死,绝对禁止主线程使用
- 如果异步操作可能失败永远不触发回调,建议把等待超时时间改成具体值,避免永久卡住
方案2:重构为异步回调模式(最推荐,符合iOS开发规范)
异步操作本身不应该设计为同步返回的方法,直接修改方法结构,把最终结果通过回调抛出,完全不会阻塞线程,代码如下:
// 修改方法签名:无返回值,新增回调参数接收最终结果 - (void)getPDFValueWithEmail:(NSString *)emailToConvert completion:(void(^)(long resultValue))completion { [MFPDFConverter createPDFFromEmail:emailToConvert completionHandler:^(long longObtainedFromBlock) { NSLog(@"Here we are"); // 回调判空避免崩溃 if (completion) { completion(longObtainedFromBlock); } }]; }
调用示例:
// 调用时在回调里处理后续逻辑 [self getPDFValueWithEmail:emailToConvert completion:^(long resultValue) { NSLog(@"拿到最终返回值:%ld", resultValue); // 后续拿到结果后的业务逻辑都写在这里 }];
注意事项:
- 该方案不会阻塞任何线程,主线程调用也不会影响界面响应,是iOS异步场景的标准实现方式
内容的提问来源于stack exchange,提问作者Alfonso Tesauro
相关产品推荐
相关产品推荐

