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

NSURLConnection started in another thread. Delegate methods not called

我在另一个线程中启动了一个 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;

在主线程上 运行 时一切正常。我怎样才能 运行 在另一个线程上连接并在同一线程上调用委托方法?

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

但是,如您所见,将它分派到后台队列没有意义,因为它已经是异步的,因此您应该从主队列启动它,并且上面的 none 是必要的。您在特殊情况下使用上述模式(例如,您使用 NSOperation 子类来管理您的请求),但通常不需要。

此外,仅供参考,有效的 iOS9、NSURLConnection 已弃用,因此无论如何您应该使用 NSURLSession。而 NSURLSession 不受此限制。

我遇到了类似的问题。我现在正在做的是在主线程中 运行ning NSURLConnection 请求 - 它是 运行ning 异步的,因此它不会减慢您的应用程序。在 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];
   }
}

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

如果您想在后台线程中接收回调,可以使用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);
               });