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

Ios 在执行下一条语句之前,如何等待NSURLConnection委托完成?,ios,objective-c,delegates,nsurlconnection,nsurlrequest,Ios,Objective C,Delegates,Nsurlconnection,Nsurlrequest,这是一个很难搜索的问题。 我发现了一个类似的问题,但公认的答案是“刷新表视图”,这对我没有帮助。我发现的其他结果倾向于c 我有一个从iPhone到Wowza服务器的应用程序。当用户点击记录时,我生成一个唯一的设备id,然后将其发送到服务器上的PHP脚本,该脚本返回一个带有配置设置的JSON文档(包括rtmp转储链接) 问题是,委托方法是异步的,但我需要在我的-(iAction)recordButtonPressed方法中的下一行代码之前获取配置设置,因为该代码是设置概要文件设置的代码,然后根据这

这是一个很难搜索的问题。 我发现了一个类似的问题,但公认的答案是“刷新表视图”,这对我没有帮助。我发现的其他结果倾向于c

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

问题是,委托方法是异步的,但我需要在我的
-(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或属性会增加无意中引入循环引用的风险

但是,有一个更好的方法:使用包装块