Objective c 在继续之前等待AFNetworking完成块(即同步)
我有一个AFNetworking同步运行的用例(详情如下)。我怎样才能做到这一点 这是我的代码片段,我已经尽可能地简化了它 我想返回成功响应,但我只得到nil(因为函数在调用块之前返回) 详细信息 所以我需要它同步运行的原因是因为我正在构建一个pod,它将在启动时引导应用程序。引导绑定命中一个服务并在本地保存一组值。然后,这些值将用于当前会话,并且不会更改。如果值发生变化,用户将获得一种奇怪的体验,因此我必须避免这种情况 如果服务中断,没关系。我们将使用默认值或查找上一个会话中保存的一些值,但无论发生什么情况,我们都不希望用户的体验在会话中发生更改Objective c 在继续之前等待AFNetworking完成块(即同步),objective-c,afnetworking-2,Objective C,Afnetworking 2,我有一个AFNetworking同步运行的用例(详情如下)。我怎样才能做到这一点 这是我的代码片段,我已经尽可能地简化了它 我想返回成功响应,但我只得到nil(因为函数在调用块之前返回) 详细信息 所以我需要它同步运行的原因是因为我正在构建一个pod,它将在启动时引导应用程序。引导绑定命中一个服务并在本地保存一组值。然后,这些值将用于当前会话,并且不会更改。如果值发生变化,用户将获得一种奇怪的体验,因此我必须避免这种情况 如果服务中断,没关系。我们将使用默认值或查找上一个会话中保存的一些值,但无
(这是一个用于A/B测试和实验的引擎——如果这有助于您“获取”用例的话)。听起来您的应用程序有一部分在启动请求完成之前无法运行。但是还有一个可以运行的部分(比如启动请求的部分)。给那个部分一个UI,告诉用户我们正忙着准备。没有阻塞UI 但是如果你必须这样做,如果AFNetworking没有提供请求的阻塞版本(这是他们的荣幸),那么你总是可以用老式的方式阻塞
- (void)pleaseDontUseThisIdea {
__block BOOL thePopeIsCatholic = YES;
[manager GET: ....^{
// ...
thePopeIsCatholic = NO;
}];
while (thePopeIsCatholic) {}
}
听起来你的应用程序有一部分在启动请求完成之前无法运行。但是还有一个可以运行的部分(比如启动请求的部分)。给那个部分一个UI,告诉用户我们正忙着准备。没有阻塞UI 但是如果你必须这样做,如果AFNetworking没有提供请求的阻塞版本(这是他们的荣幸),那么你总是可以用老式的方式阻塞
- (void)pleaseDontUseThisIdea {
__block BOOL thePopeIsCatholic = YES;
[manager GET: ....^{
// ...
thePopeIsCatholic = NO;
}];
while (thePopeIsCatholic) {}
}
忽略我们通常不希望发出同步网络请求的事实,传统的解决方案是使用信号量:
- (id)sendForUrl:(NSURL *)url {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block id response;
[manager GET:url.absoluteString parameters:nil success: ^(AFHTTPRequestOperation *operation, id responseObject) {
response = responseObject;
NSLog(@"JSON: %@", responseObject);
dispatch_semaphore_signal(semaphore);
} failure: ^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return response;
}
这里有两个问题:
completionQueue
设置为其他后台队列。默认情况下,AFHTTPRequestOperationManager
将使用这些完成块的主队列。如果您阻止该线程,直到完成阻止在同一线程上运行,您将死锁(即,您的应用程序将冻结)为了完整性起见,我要指出,当有人问“如何使某个异步方法同步运行”时,正确的答案总是“你没有”。相反,您通常采用异步模式,例如更改方法以获取块参数:
- (void)sendForUrl:(NSURL *)url completionHandler:(void (^)(id responseObject, NSError *error))completionHandler {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
[manager GET:url.absoluteString parameters:nil success: ^(AFHTTPRequestOperation *operation, id responseObject) {
if (completionHandler) {
completionHandler(responseObject, nil);
}
} failure: ^(AFHTTPRequestOperation *operation, NSError *error) {
if (completionHandler) {
completionHandler(nil, error);
}
}];
}
然后,您可以这样调用它,提供一个完成处理程序块:
[object sendForURL:url completionHandler:^(id responseObject, NSError *error) {
// use responseObject and/or error here
}];
// don't use them here
忽略我们通常不希望发出同步网络请求的事实,传统的解决方案是使用信号量:
- (id)sendForUrl:(NSURL *)url {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block id response;
[manager GET:url.absoluteString parameters:nil success: ^(AFHTTPRequestOperation *operation, id responseObject) {
response = responseObject;
NSLog(@"JSON: %@", responseObject);
dispatch_semaphore_signal(semaphore);
} failure: ^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return response;
}
这里有两个问题:
completionQueue
设置为其他后台队列。默认情况下,AFHTTPRequestOperationManager
将使用这些完成块的主队列。如果您阻止该线程,直到完成阻止在同一线程上运行,您将死锁(即,您的应用程序将冻结)为了完整性起见,我要指出,当有人问“如何使某个异步方法同步运行”时,正确的答案总是“你没有”。相反,您通常采用异步模式,例如更改方法以获取块参数:
- (void)sendForUrl:(NSURL *)url completionHandler:(void (^)(id responseObject, NSError *error))completionHandler {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
[manager GET:url.absoluteString parameters:nil success: ^(AFHTTPRequestOperation *operation, id responseObject) {
if (completionHandler) {
completionHandler(responseObject, nil);
}
} failure: ^(AFHTTPRequestOperation *operation, NSError *error) {
if (completionHandler) {
completionHandler(nil, error);
}
}];
}
然后,您可以这样调用它,提供一个完成处理程序块:
[object sendForURL:url completionHandler:^(id responseObject, NSError *error) {
// use responseObject and/or error here
}];
// don't use them here
真棒的回答。我担心我会看到一些复杂的调度风格的东西,但这两个建议都很好,完全有意义。谢谢真棒的回答。我担心我会看到一些复杂的调度风格的东西,但这两个建议都很好,完全有意义。谢谢除非信号量是静态的,否则
dispatch\u release
it不是一个好主意吗?如果使用ARC,这将为您解决。如果不使用ARC,那么,是的,您将分派\u release
它。每天学习新的东西!很不错的。谢谢你的回答。关于派遣的事情,我的意思是我真的不想让霍恩AFN按照我需要的方式行事。我想我会做的是@danh的第一个建议,那就是在我的API中公开一个BOOL,类似于“bootstrappingIsDone”,这样使用我的Pod的开发人员就可以处理他们认为合适的等待。尽管如此,在我这么做之前,我想我会快速浏览一下NS*API,看看是否可以使用它。(我对ObjC非常陌生,所以仍在研究如何将所有这些结合起来)。谢谢除非信号量是静态的,否则dispatch\u release
it不是一个好主意吗?如果使用ARC,这将为您解决。如果不使用ARC,那么,是的,您将分派\u release
它。每天学习新的东西!很不错的。谢谢你的回答。关于派遣的事情,我的意思是,我真的不想让霍恩·阿夫恩按照我需要的方式行事