Ios 在执行下一条语句之前,如何等待NSURLConnection委托完成?
这是一个很难搜索的问题。 我发现了一个类似的问题,但公认的答案是“刷新表视图”,这对我没有帮助。我发现的其他结果倾向于c 我有一个从iPhone到Wowza服务器的应用程序。当用户点击记录时,我生成一个唯一的设备id,然后将其发送到服务器上的PHP脚本,该脚本返回一个带有配置设置的JSON文档(包括rtmp转储链接) 问题是,委托方法是异步的,但我需要在我的Ios 在执行下一条语句之前,如何等待NSURLConnection委托完成?,ios,objective-c,delegates,nsurlconnection,nsurlrequest,Ios,Objective C,Delegates,Nsurlconnection,Nsurlrequest,这是一个很难搜索的问题。 我发现了一个类似的问题,但公认的答案是“刷新表视图”,这对我没有帮助。我发现的其他结果倾向于c 我有一个从iPhone到Wowza服务器的应用程序。当用户点击记录时,我生成一个唯一的设备id,然后将其发送到服务器上的PHP脚本,该脚本返回一个带有配置设置的JSON文档(包括rtmp转储链接) 问题是,委托方法是异步的,但我需要在我的-(iAction)recordButtonPressed方法中的下一行代码之前获取配置设置,因为该代码是设置概要文件设置的代码,然后根据这
-(iAction)recordButtonPressed
方法中的下一行代码之前获取配置设置,因为该代码是设置概要文件设置的代码,然后根据这些设置进行记录
我已经意识到我可以像现在一样按下-recordButtonPressed
中的NSURLConnection
,然后在委托方法connectiondFinishLoading
中继续执行设置代码(或者只是封装设置并从那里调用它)但这是为了功能而牺牲连贯的设计,这太糟糕了
是否有一些简单的waitUntilDelegateIsFinished:(BOOL)nonAsyncFlag
标志我可以发送给委托人,这样我就可以进行从web提取数据的顺序操作?为什么不使用?为什么不使用
我已经意识到我可以使NSURLConnection in-recordButton像当前一样被按下,然后在委托方法ConnectiondFinishLoading中继续设置代码(或者只是封装设置并从那里调用方法),但这牺牲了功能的一致性设计,这很糟糕
您已经分析并理解了情况,并且完美地描述了可能的解决方案。我只是不同意你的结论。这种事情经常发生:
- (void) doPart1 {
// do something here that will eventually cause part2 to be called
}
- (void) doPart2 {
}
您可以通过调用玩各种游戏,使其更加优雅和通用,但我的建议是,不要反对框架,因为您所描述的正是异步的本质。(并且不要在主线程上使用同步请求,因为这会阻塞主线程,而主线程是不允许的。)
事实上,在事件驱动的框架中,“等待”这个概念本身就是一种诅咒
我已经意识到我可以使NSURLConnection in-recordButton像当前一样被按下,然后在委托方法ConnectiondFinishLoading中继续设置代码(或者只是封装设置并从那里调用方法),但这牺牲了功能的一致性设计,这很糟糕
您已经分析并理解了情况,并且完美地描述了可能的解决方案。我只是不同意你的结论。这种事情经常发生:
- (void) doPart1 {
// do something here that will eventually cause part2 to be called
}
- (void) doPart2 {
}
您可以通过调用玩各种游戏,使其更加优雅和通用,但我的建议是,不要反对框架,因为您所描述的正是异步的本质。(并且不要在主线程上使用同步请求,因为这会阻塞主线程,而主线程是不允许的。)
事实上,在事件驱动的框架中,“等待”这一概念本身就是一种诅咒。将异步NSURLConnection请求包装在一个助手方法中,该方法将完成块作为参数:
-(void)asyncDoSomething:(void(^)(id结果)completionHandler;
此方法应在nsurlconnectionelegate
中实现。有关详细信息,请参阅下面的示例实现和注释
在其他地方,在您的行动方法中:
设置完成处理程序。块将在主线程上进一步调度,然后执行任何适当的操作来更新表数据,除非结果是错误,在这种情况下,您应该显示警报
- (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中。适当时,使用正确的参数调用它。但是,将块作为ivar或属性会增加无意中引入循环引用的风险
但是,有一种更好的方法:包装程序块将立即被调度到挂起的串行调度队列(作为ivar保留)。由于队列挂起,它们将不会执行任何块。只有在队列恢复后,才会执行块。您可以在连接IDfinish:
和连接中恢复队列ActionDidFailWitherRor:
(见下文):
在您的NSURLConnectionLegate中:
-(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];
}
然后在NSURLConnectionLegate中,向处理程序发送一个命令,并恢复
处理程序队列:
- (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
}
将异步NSURLConnection请求包装在助手方法中,该方法将完成块作为参数:
-(void)asyncDoSomething:(void(^)(id结果)completionHandler;
此方法应在nsurlconnectionelegate
中实现。有关详细信息,请参阅下面的示例实现和注释
在其他地方,在您的行动方法中:
设置完成处理程序。块将在主线程上进一步调度,然后执行任何适当的操作来更新表数据,除非结果是错误,在这种情况下,您应该显示警报
- (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中。适当时,使用正确的参数调用它。但是,将块作为ivar或属性会增加无意中引入循环引用的风险
但是,有一个更好的方法:使用包装块