iOS 在块完成之前停止块执行

iOS Stop block execution from progressing until block has finished

我在 iOS 应用程序中有一个方法,它应该 return 一个 bool 值,具体取决于网络调用是否成功。

Web 调用的结构是将一个块作为回调参数,当 Web 调用有结果时调用该回调。基于该结果,我的方法需要 return 一个 True/False 值。

所以,我需要停止执行,而不是先得到 return 的结果。

在查看了其他人分享的一些示例后,我正在尝试通过信号量实现此目的,但从未调用过回调,如果我删除信号量,则始终会调用回调。

我在这里错过了什么?

+ (BOOL)getUserInformation {
__block BOOL flag = false;

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

[[WebServicesManager sharedManager] getUserInformationWithCallback:^(NSInteger statusCode, NSString *response, NSDictionary *responseHeaders, id obj, NSError *error) {

    if (error) {
        //Handle error case and perform appropriate cleanup actions.
    }
    else
    {
        //Save user information
        flag = true;
    }

    dispatch_semaphore_signal(semaphore);
}];

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

return flag;
}

我在 if(error) 上设置了一个断点来检查回调是否被调用,它没有,除非我删除信号量。

我可以给这个方法它自己的回调块,或者我可以给包含 class 一个委托并实现我需要的,但我真的想让这个方法起作用。

WebServicesManager 可能正在信号量正在等待的同一线程上分派它的块。

正如@Rob 在评论中正确提到的那样,这很可能不是在主线程上做的好主意;而是使用异步模型,不要阻塞主线程可能几分钟,直到在某些情况下连接可能超时,冻结你的 UI.

您无疑陷入了僵局,因为您在 Web 服务管理器(或正在使用的 API 调度其完成处理程序的同一线程上使用信号量。

如果你想要一个既能避免死锁又能避免阻塞主线程的陷阱,你可以这样做:

+ (void)getUserInformation:(nonnull void (^)(BOOL))completionHandler {
    [[WebServicesManager sharedManager] getUserInformationWithCallback:^(NSInteger statusCode, NSString *response, NSDictionary *responseHeaders, id obj, NSError *error) {
        if (error) {
            completionHandler(false);
        } else {
            //Save user information
            completionHandler(true);
        }
    }];
}

然后,而不是做这样的事情:

BOOL success = [YourClass getUserInformation];
if (success) {
    ...
}

您可以改为:

[YourClass getUserInformation:^(BOOL success) {
    if (success) {
        ...
    }
}];

// but do not try to use `success` here ... put everything
// contingent upon success inside the above completion handler