iOS停止块执行从进度到块完成

时间:2016-01-13 10:41:40

标签: ios objective-c-blocks semaphore

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

Web调用的结构使得它将块作为回调参数,并在Web调用具有结果时调用回调。基于该结果,我的方法需要返回True / False值。

所以,我需要在没有结果返回的情况下停止执行任何进一步的进展。

我试图通过信号量来实现这一点,在查看其他人共享的一些示例之后,但是从不调用回调,如果我删除信号量,则总是调用回调。

我在这里缺少什么?

+ (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)上设置了一个断点来检查回调是否被调用,它不会,除非我删除信号量。

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

2 个答案:

答案 0 :(得分:2)

WebServicesManager可能在信号量等待的同一个线程上调度它的块。

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

答案 1 :(得分:0)

您无疑是死锁,因为您在同一个线程上使用信号量,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