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
我在 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