AFNetworking-2 waitUntilFinished无法正常工作

我知道还有另一个类似的问题 ,但是它适用于较旧版本的AFNetworking,并且无论如何都没有真正回答它。

我有以下代码:

AFHTTPRequestOperationManager* manager = [AFHTTPRequestOperationManager manager]; manager.securityPolicy.allowInvalidCertificates = YES; manager.requestSerializer = [AFJSONRequestSerializer serializer]; [manager.requestSerializer setAuthorizationHeaderFieldWithUsername: currentUser() password: currentPassword()]; __block NSDictionary* response = nil; AFHTTPRequestOperation* operation = [manager GET: @"https://10.20.30.40:8765/foobar" parameters: [NSDictionary dictionary] success:^(AFHTTPRequestOperation* operation, id responseObject){ response = responseObject; NSLog(@"response (block): %@", response); } failure:^(AFHTTPRequestOperation* operation, NSError* error){ NSLog(@"Error: %@", error);} ]; [operation waitUntilFinished]; NSLog(@"response: %@", response); ... 

如果我运行它,我将在日志中看到的是:

 2013-12-09 09:26:20.105 myValve[409:60b] response: (null) 2013-12-09 09:26:20.202 myValve[409:60b] response (block): { F00005 = ""; F00008 = ""; F00013 = ""; } 

waitUntilFinished 之后NSLog waitUntilFinished触发。 我预计它会第二次开火。 我错过了什么?

几点想法:

  1. 问题是waitUntilFinished将等待核心网络操作完成,但它不会等待successfailure完成块。 如果要等待完成块,可以使用信号量:

     __block NSDictionary* response = nil; dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); AFHTTPRequestOperation* operation = [manager GET: @"https://10.20.30.40:8765/foobar" parameters: [NSDictionary dictionary] success:^(AFHTTPRequestOperation* operation, id responseObject){ response = responseObject; NSLog(@"response (block): %@", response); dispatch_semaphore_signal(semaphore); } failure:^(AFHTTPRequestOperation* operation, NSError* error){ NSLog(@"Error: %@", error); dispatch_semaphore_signal(semaphore); }]; NSLog(@"waiting"); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // [operation waitUntilFinished]; NSLog(@"response: %@", response); 

    或者,您可以将它包装在您自己的并发NSOperation子类中,在AFHTTPRequestOperation完成块中发布isFinished ,从而消除过程中的semaphore

    注意,如果在主队列上执行信号量,请确保指定completionQueue ,因为如果没有,则AFNetworking默认将完成处理程序分派到主队列,并且您可以死锁。

  2. waitUntilFinished ,你永远不应该阻止主队列(可怜的用户体验,你的应用程序可能会被监视程序进程杀死等等),所以如果你是从主队列执行此操作,我不鼓励使用waitUntilFinished或信号量。 最好只在完成块中启动您需要的任何内容,让主队列在此异步网络操作正在进行时继续执行,例如:

     [activityIndicatorView startAnimating]; AFHTTPRequestOperation* operation = [manager GET: @"https://10.20.30.40:8765/foobar" parameters: [NSDictionary dictionary] success:^(AFHTTPRequestOperation* operation, id responseObject){ // do whatever you want with `responseObject` here // now update the UI, eg: [activityIndicatorView stopAnimating]; [self.tableView reloadData]; } failure:^(AFHTTPRequestOperation* operation, NSError* error){ // put your error handling here // now update the UI, eg: [activityIndicatorView stopAnimating]; }]; // NSLog(@"waiting"); // dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // // [operation waitUntilFinished]; // NSLog(@"response: %@", response); 

听起来您希望让模型让UI在模型对象完成更新时进行任何必要的更新。 因此,您可以使用自己的块参数,以便视图控制器可以告诉模型对象在完成时要执行的操作(而不是使用waitUntilFinished或信号量来使网络操作阻塞主队列)。 例如,假设您的模型有一些像这样的方法:

 - (void)updateModelWithSuccess:(void (^)(void))success failure:(void (^)(NSError *error))failure { AFHTTPRequestOperationManager* manager = [AFHTTPRequestOperationManager manager]; manager.securityPolicy.allowInvalidCertificates = YES; manager.requestSerializer = [AFJSONRequestSerializer serializer]; [manager.requestSerializer setAuthorizationHeaderFieldWithUsername: currentUser() password: currentPassword()]; AFHTTPRequestOperation* operation = [manager GET: @"https://10.20.30.40:8765/foobar" parameters: [NSDictionary dictionary] success:^(AFHTTPRequestOperation* operation, id responseObject){ // do your model update here // then call the success block passed to this method (if any), // for example to update the UI if (success) success(); } failure:^(AFHTTPRequestOperation* operation, NSError* error){ NSLog(@"Error: %@", error); // if caller provided a failure block, call that if (failure) failure(error); }]; } 

然后您的视图控制器可以执行以下操作:

 [modelObject updateModelWithSuccess:^{ // specify UI updates to perform upon success, eg // stop activity indicator view, reload table, etc. } failure:^(NSError *error){ // specify any UI updates to perform upon failure }] 

最后,您的代码可以使用AFNetworking使用的相同样式的完成块。 如果您希望模型返回信息,您可以将其他参数添加到完成块本身,但我认为上面说明了基本概念。