将您的异步 NSURLConnection 请求包装在一个辅助方法中,该方法具有一个完成块作为参数:
-(void) asyncDoSomething:(void(^)(id result)completionHandler ;
此方法应在NSURLConnectionDelegate
. 有关详细信息,请参阅下面的示例实现和注释。
在其他地方,在您的操作方法中:
设置完成处理程序。该块将在主线程上进一步分派,然后执行任何适当的操作来更新表数据,除非结果是错误,在这种情况下您应该显示警报。
- (IBAction) recordButtonPressed
{
[someController asyncConnectionRequst:^(id result){
if (![result isKindOfClass:[NSError class]]) {
dispatch_async(dispatch_get_main_queue(), ^{
// We are on the main thread!
someController.tableData = result;
});
}
}];
}
该方法的实现asyncConnectionRequst:
可以如下工作:获取块并将其保存在 ivar 中。在适当的时候用正确的参数调用它。但是,将块作为 ivars 或属性会增加无意中引入循环引用的风险。
但是,有一个更好的方法:一个包装块将立即分派到一个挂起的串行调度队列——它作为一个 ivar 保存。由于队列被挂起,它们不会执行任何块。只有在队列恢复之后,块才会执行。您在connectionDidFinish:
and中恢复队列connectionDidFailWithError:
(见下文):
在你的 NSURLConnectionDelegate 中:
-(void) asyncConnectionRequst:(void(^)(id result)completionHandler
{
// Setup and start the connection:
self.connection = ...
if (!self.connection) {
NSError* error = [[NSError alloc] initWithDomain:@"Me"
code:-1234
userInfo:@{NSLocalizedDescriptionKey: @"Could not create NSURLConnection"}];
completionHandler(error);
});
return;
}
dispatch_suspend(self.handlerQueue); // a serial dispatch queue, now suspended
dispatch_async(self.handlerQueue, ^{
completionHandler(self.result);
});
[self.connection start];
}
然后在 NSURLConnectionDelegate 中,调度一个处理程序并恢复处理程序队列:
- (void) connectionDidFinishLoading:(NSURLConnection*)connection {
self.result = self.responseData;
dispatch_resume(self.handlerQueue);
dispatch_release(_handlerQueue), _handlerQueue = NULL;
}
同样,当发生错误时:
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
self.result = error;
dispatch_resume(self.handlerQueue);
dispatch_release(_handlerQueue), _handlerQueue = NULL;
}
还有更好的方法,但是涉及一些更基本的帮助类来处理异步架构,最终使您的异步代码看起来像是同步的:
-(void) doFourTasksInAChainWith:(id)input
{
// This runs completely asynchronous!
self.promise = [self asyncWith:input]
.then(^(id result1){return [self auth:result1]);}, nil)
.then(^(id result2){return [self fetch:result2];}, nil)
.then(^(id result3){return [self parse:result3];}, nil)
.then(^(id result){ self.tableView.data = result; return nil;}, ^id(NSError* error){ ... })
// later eventually, self.promise.get should contain the final result
}