GCD与NSURLConnection

我正在使用GCDasynchronous发送HTTP请求。 以下是不起作用的代码:

 dispatch_async(connectionQueue, ^{ NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; [request setURL:[NSURL URLWithString:[NSString stringWithFormat:someURL]]]; NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; [connection start];//Not working }); 

上面的代码根本不起作用。 我在NSURLConnectionDelegate的方法中没有收到任何callback。

但是,当我尝试下面的代码,一切工作正常,我得到适当的callback

 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; [request setURL:[NSURL URLWithString:[NSString stringWithFormat:someURL]]]; NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; dispatch_async(connectionQueue, ^{ [connection start]; // working fine. But WHY ???? }); 

有人可以解释这个块/ GCD的怪异行为吗?

在你的代码示例的第一部分试试这个 –

 dispatch_async(dispatch_get_main_queue(), ^(void){ NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; [connection start]; } 

如果将连接放在后台队列中,则会在队列完成后将其取消,因此不会获得委托callback。 连接可以在主队列中,因此它将停留在主要运行循环中以进行callback。 或者,您可以按照其他人的build议创build自己的runloop,以处理您的后台操作。

当使用NSURLConnection进行asynchronous通信时,您需要让它实例化的线程附加到其RunLoop的连接,以便让该线程轮询相同连接的委托方法。

下面是不依赖主线程的RunLoop来asynchronous实例化NSURLConnection的正确方法:

 // Done within a Grand Central Dispatch block, or NSOperation. // We do not start the connection here because we still need to attach the connection to the RunLoop of the current thread and handle how it will communicate responses back to the caller. theConnection = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:NO]; // A previously instantiated NSOperationQueue for managing the delegate callbacks if-and-when they occur. // [theConnection setDelegateQueue:delegateQueue]; /* // Other NSURLConnection logic, etc. */ // We start the connection manually after properly establishing how it will poll and respond to events. [theConnection start]; // This is for the RunLoop of the current thread. (Only needed for < iOS 6 compatibility) // If this method is executed inside a GCD block or NSOperation, it will be the RunLoop of the thread run in-parallel to the Main Thread. [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:30.0]]; // From here, you can alter the time interval to coincide with a specific "time-out" event you'd like to occur. 

其中“theConnection”是当前types“NSURLConnection”的成员variables。 此外,您将需要创build一个NSOperationQueue成员variables来pipe理代理callback,一旦您的连接收到响应。 这些调用将被asynchronous传回到运行连接的线程。

从那里,你可以使用适当的NSURLConnection委托方法返回数据。

使用Grand Central Dispatch或Operation Queues的好处是线程和RunLoop机制已经内置; 你将不必手动分配一个额外的线程与它自己的RunLoop。 这消除了创build后台线程以pipe理asynchronous服务器调用的两步冗余。

我希望这足以让你在正确的道路上为你的应用程序创build一个真正的asynchronousnetworking模型。 🙂

NSURLConnection将始终执行在创build线程(alloc init)上的数据获取。 这解释了为什么它会以第二种方式工作。 第一种方法可以工作,但线程在您能够从NSURLConnection接收到任何信息之前就会死亡。 NSURLConnection已经允许asynchronous下载,但是如果你想要asynchronous运行数据处理,你应该使用下面的方法:

 + (void)sendAsynchronousRequest:(NSURLRequest *)request queue:(NSOperationQueue *)queue completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler 

这种方法有一些限制,如authentication是有限的,你不能跟踪有多less文件已被下载到目前为止。 您还必须指定一个您创build的NSOperationQueue,默认队列是主循环队列。

您可以为该连接启动一个临时的NSOperationQueue。 只有连接需要时,该队列才能存活。 基本上NSOperationQueue确保你有委托callback排队和旋转线程来处理每个代表callback处理。 (在大多数情况下,当下载新数据时,或者连接失败时,连接完成加载等等,将进入hibernate状态并恢复相同的后台线程)。 一旦你有这个队列设置委托callback将开始进入你的应用程序。

 dispatch_async(connectionQueue, ^{ connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; NSOperationQueue __autoreleasing *tempQueue = [[NSOperationQueue alloc] init]; [connection setDelegateQueue:tempQueue]; [connection start]; }); 

如果你select了RunLoop,那么pipe理runloop会给你带来额外的负担。