我知道有another similar question,但是它是针对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 = "";
}
NSLog
之后的waitUntilFinished
首先触发。我希望它能排第二。我想念什么? 最佳答案
有两个想法:
waitUntilFinished
将等待核心网络操作完成,但不会等待success
或failure
完成块。如果要等待完成块,可以使用信号灯:__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
子类中,将isFinished
张贴在AFHTTPRequestOperation
完成块中,从而消除该过程中的semaphore
。注意,如果在主队列上进行信号量,请确保指定
completionQueue
因为在没有这种情况的情况下,AFNetworking默认将完成处理程序分派(dispatch)到主队列,并且您可能会死锁。 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, e.g.:
[activityIndicatorView stopAnimating];
[self.tableView reloadData];
}
failure:^(AFHTTPRequestOperation* operation, NSError* error){
// put your error handling here
// now update the UI, e.g.:
[activityIndicatorView stopAnimating];
}];
// NSLog(@"waiting");
// dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// // [operation waitUntilFinished];
// NSLog(@"response: %@", response);
听起来您想让模型对象完成更新后,让模型让UI进行任何必要的更新。因此,您可以使用自己的块参数,以便 View Controller 可以告诉模型对象完成后的操作(而不是使用
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);
}];
}
然后,您的 View Controller 可以执行以下操作:
[modelObject updateModelWithSuccess:^{
// specify UI updates to perform upon success, e.g.
// stop activity indicator view, reload table, etc.
} failure:^(NSError *error){
// specify any UI updates to perform upon failure
}]
最重要的是,您的代码可以使用与AFNetworking使用的样式相同的完成块。如果希望模型将信息传递回去,则可以将其他参数本身添加到完成模块中,但是我想上面的示例说明了基本思想。