NSURLConnection在另一个线程中开始。委托方法未调用

时间:2015-08-21 18:24:24

标签: ios objective-c multithreading nsurlconnection grand-central-dispatch

我在另一个线程中启动NSURLConnection:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
        ^{
            NSURLConnection *connection = [NSURLConnection connectionWithRequest:[request preparedURLRequest] delegate:self];
            [connection start];
         });

但是我的委托方法没有被调用:

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData*)data;

在主线程上运行时一切都很好。如何在另一个线程上运行连接并获取在同一线程上调用的委托方法?

3 个答案:

答案 0 :(得分:5)

GCD隐式创建,销毁,重用线程,并且您调用的线程有可能会在之后立即停止存在。这可能导致代理没有收到任何回调。

如果您希望在后台线程中收到回调,可以使用setDelegateQueuesendAsynchronousRequest:queue:completionHandler:方法:

NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:request
                                                          delegate:self
                                                  startImmediately:NO];
[connection setDelegateQueue:[[NSOperationQueue alloc] init]];
[connection start];

通过GCD在后台线程中启动NSURLConnection的最简单方法是:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
               ^{
                   NSURLResponse* response = nil;
                   NSError* error = nil;
                   [NSURLConnection sendSynchronousRequest:request] returningResponse:&response error:&error];
                   NSLog(@"%@", response);
               });

答案 1 :(得分:2)

是的,这是众所周知的NSURLConnection行为,因为它需要一个运行循环来处理委托事件。最常见的解决方案是(a)使用initWithRequest:delegate:startImmediately:对其进行实例化,其中startImmediatelyFALSE; (b)手动scheduleInRunLoop:forMode:在主运行循环中安排它;然后(c)start连接。

但是,正如你在这里所说的那样,没有必要将它分配给后台队列,因为它已经是异步的,所以你应该从主队列中启动它,而上面没有一个是必要。您在特殊情况下使用上述模式(例如,您使用NSOperation子类来管理您的请求),但通常不需要。

另外,仅供参考,有效的iOS9,NSURLConnection已被弃用,因此您应该使用NSURLSession。并且NSURLSession不受此限制。

答案 2 :(得分:1)

我有类似的问题。我现在正在做的是在主线程中运行NSURLConnection请求 - 它以异步方式运行,因此它不会减慢你的应用程序的速度。在connectionDidFinishLoading中,我运行以下代码来处理我的调用结果。我执行检查,因为我有NSURLConnection调用,可能会触发其他网络调用。由于他们已经在后台线程上运行,我不想开始新的。

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
   if ([NSThread isMainThread]) {
      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
         //Background Thread
         [self processFinishLoading:connection];
      });
   }
   else {
      [self processFinishLoading:connection];
   }
}