在执行下一条语句之前,如何等待NSURLConnection委托完成?

这是一个很难search。 我发现了一个类似的问题, iOS 5在填充表之前等待委托完成? ,但接受的答案是“刷新表视图”,这并没有帮助我。 我发现的其他结果往往是在C#中。

我有一个从iPhonestream到Wowza服务器的应用程序。 当用户点击logging时,我生成一个唯一的设备ID,然后将其发送到服务器上的PHP脚本,该脚本返回带有configuration设置(包括rtmp转储链接)的JSON文档。

问题是,委托方法是asynchronous的,但我需要在我的- (IBAction)recordButtonPressed方法的下一行代码之前获取configuration设置,因为代码是什么设置configuration文件设置,然后基于这些设置进行logging。

我已经意识到,我可以像现在一样在-recordButtonPressed创buildNSURLConnection ,然后在委托方法connectionDidFinishLoading (或者只是封装设置和方法从那里调用它) 内部继续安装代码,但是这会牺牲function的一致性devise,吮吸。

是否没有一些简单的waitUntilDelegateIsFinished:(BOOL)nonAsyncFlag标志我可以发送给委托,所以我可以从网上拉数据的顺序操作?

我已经意识到,我可以像现在一样在-recordButtonPressed中创buildNSURLConnection,然后在委托方法connectionDidFinishLoading(或者只是封装设置和方法从那里调用它)内部继续安装代码,但是这会牺牲function的一致性devise,吮吸。

你已经分析和了解情况,你已经完美地描述了可能的解决scheme。 我只是不同意你的结论。 这种事情总是在发生:

 - (void) doPart1 { // do something here that will eventually cause part2 to be called } - (void) doPart2 { } 

你可以通过调用来玩各种游戏,使其更加优雅和普遍,但是我的build议是,不要打架,因为你所描述的正是asynchronous的本质。 (并且不要在主线程上使用同步请求,因为这会阻塞主线程,这是一个不允许的)。

事实上,在事件驱动的框架中,“等到”这个概念是令人厌恶的。

为什么不使用同步请求 ?

将你的asynchronousNSURLConnection请求封装在一个以完成块作为参数的辅助方法中:

-(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:的实现asyncConnectionRequst: 可以按如下方式工作:取块并保存在ivar中。 适当的时候用正确的参数调用它。 但是,将块作为ivars或属性会增加无意中引入循环引用的风险。

但是,有一个更好的方法:一个包装块将被立即调度到暂停的串行调度队列 – 这是作为一个伊维尔举行。 由于队列被挂起,他们不会执行任何块。 只有在队列恢复之后,该块才会执行。 你在你的connectionDidFinish:connectionDidFailWithError:恢复队列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; } 

还有更好的方法,但是涉及到几个基本的帮助类,它们处理asynchronous体系结构,在一天结束时,你的asynchronous代码看起来像是同步的:

 -(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 }