Ios 如何使程序等待异步NSURLConnection完成,然后再继续执行下一个命令?

Ios 如何使程序等待异步NSURLConnection完成,然后再继续执行下一个命令?,ios,web-services,Ios,Web Services,如何使程序在进入下一行代码之前等待异步NSURLConnection完成 SetDelegate *sjd= [SetDelegate alloc]; NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:post delegate:sjd]; [connection start]; 这就是我启动连接和处理委托中接收的数据的方式,但我希望在继续之前等待连接结束,这主要是因为这是一个for循环,它必须为数据库中

如何使程序在进入下一行代码之前等待异步NSURLConnection完成

SetDelegate *sjd= [SetDelegate alloc];
NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:post delegate:sjd];
[connection start];
这就是我启动连接和处理委托中接收的数据的方式,但我希望在继续之前等待连接结束,这主要是因为这是一个for循环,它必须为数据库中的每个元素运行

我需要把数据从手机数据库到一个远程数据库,数据成功后,在手机数据库中的数据被删除。我正在检查手机数据库中的每个元素,并开始连接,这就是为什么我不知道如何从循环中完成下一步工作。对于objective-c编程,我是一个初学者,所以我不确定这是否是正确的方法


使调用同步不是一个选项,因为它会阻止程序,并且我有一个进度条应该显示出来。

NSURLConnection已经是异步的。只需实现委托方法。如果要更新主线程上的UI(例如进度条),可以在
didReceiveData中进行更新。

或者看看

如果你真的想让它等待,为什么还要使用异步调用呢?请改用同步调用:

NSURLResponse* response = nil;
NSData* data = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:nil]

这种方法会阻止它执行的线程,所以你应该确定你想这么做!我说过它会阻塞吗?:)

你的问题有点奇怪。你不可能限制这个问题。您不能让一行代码“等待”一个进程完成而不阻塞某些内容,在本例中,不管循环运行在哪个线程中

如果愿意,您可以使用同步调用,它不会阻止您的应用程序,它只会阻止在其上执行的线程。在您的示例中,您有一个不断获取远程数据的循环,您希望您的UI能够反映这一点,直到完成为止。但你不希望你的用户界面被封锁。这意味着,这个包含循环的线程必须已经在后台线程上,这样您就可以在循环中随意执行同步调用,而不阻塞UI线程。如果循环在UI线程上,则需要更改它以执行所需操作

您也可以使用异步连接来实现这一点。在这种情况下,您的操作可能实际完成得更快。您可以同时处理多个请求。如果这样做,循环可以保留在UI线程上,您只需要跟踪所有连接,以便在连接完成时可以将该状态传达给相关控制器。您需要IVAR来跟踪加载状态,并在加载完成时使用协议或NSNotification进行通信

编辑:添加了后台线程上的同步调用示例

如果您希望循环仅在所有请求都完成且不阻塞UI线程时才完全完成,下面是一个简单的示例:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // post an NSNotification that loading has started
    for (x = 0; x < numberOfRequests; x++) {
        // create the NSURLRequest for this loop iteration
        NSURLResponse *response = nil;
        NSError *error = nil;
        NSData *data = [NSURLConnection sendSynchronousRequest:request
                                             returningResponse:&response
                                                         error:&error];
        // do something with the data, response, error, etc
    }
    // post an NSNotification that loading is finished
});
dispatch\u async(dispatch\u get\u global\u queue(dispatch\u queue\u PRIORITY\u DEFAULT,0)^{
//发布加载已开始的通知
对于(x=0;x

任何需要显示加载状态的对象都应该观察并处理您在此处发布的通知。该循环将在后台线程上同步执行所有请求,用户界面线程将被解锁并响应。这不是实现这一点的唯一方法,事实上,我自己也会使用异步连接,但这是一个简单的示例,说明如何获取所需的内容。

您说要等待异步调用完成,所以我假设您正在调用在单独线程中发布的代码


我建议您看看新的
sendAsynchronousRequest
方法。我已经知道,当连接完成/超时/失败时,它会通知其代理。我之所以把你提到这篇文章,是因为听起来你在努力实现一些与我当时非常相似的东西,而这个
下载包装器
类对我来说完美无瑕。请注意,它在iOS5中是新的。

如果您只想知道它何时完成,而不真正关心任何数据,只需使用
NSNotificationCenter
发布通知并让您的视图订阅即可

代表-完成后发布通知

-(void) connectionDidFinishLoading:(NSURLConnection*)connection {
    [[NSNotificationCenter defaultCenter] postNotificationName:@"NSURLConnectionDidFinish" object:nil];
}
查看-添加观察者并在观察时运行一些代码

-(void) viewDidLoad {

[[NSNotificationCenter defaultCenter] addObserver:self
                                          selector:@selector(yourCleanupMethod)
                                               name:@"NSURLConnectionDidFinish"
                                              object:nil];
}

-(void) yourCleanupMethod {
    // finish up

    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
现在,如果需要将简单对象作为数据传回,可以尝试在通知中加载对象参数,如下所示:

[[NSNotificationCenter defaultCenter] postNotificationName:@"NSURLConnectionDidFinish" object:yourDataObject];
-(void) viewDidLoad {

// Notice the addition to yourCleanupMethod
[[NSNotificationCenter defaultCenter] addObserver:self
                                          selector:@selector(yourCleanupMethod:)
                                               name:@"NSURLConnectionDidFinish"
                                              object:nil];
}

-(void) yourCleanupMethod:(NSNotification *)notif {
    // finish up
    id yourDataObject = [notif object];

    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
然后更改视图和清理签名,如下所示:

[[NSNotificationCenter defaultCenter] postNotificationName:@"NSURLConnectionDidFinish" object:yourDataObject];
-(void) viewDidLoad {

// Notice the addition to yourCleanupMethod
[[NSNotificationCenter defaultCenter] addObserver:self
                                          selector:@selector(yourCleanupMethod:)
                                               name:@"NSURLConnectionDidFinish"
                                              object:nil];
}

-(void) yourCleanupMethod:(NSNotification *)notif {
    // finish up
    id yourDataObject = [notif object];

    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
现在我发现自己需要的不仅仅是这些,所以我最终创建了一个单例来处理我的所有请求。由于
nsurlconnectionelegate
中的所有委托方法都为特定连接提供了
NSURLConnection
的实例,因此您只需将可变数据对象存储在字典中,并通过连接每次查找即可。从那里我有了一个方法签名,它接受对象和选择器,因为我与连接相关联,所以在一切结束后,我可以通过对该对象执行选择器将该可变数据对象传递给请求者

我不会在这里包含所有这些代码,但这可能会帮助您思考什么是可能的。我发现我在进行web服务调用时有很多代码,所以将所有内容都包装在一个罪恶中