所以真正的问题不在于运行块的线程的生命周期,而是该特定线程不会配置并运行 runloop 来接收从连接返回的任何事件。
那么你如何解决这个问题?有不同的选择需要考虑。我可以列出一些,我相信其他人会列出更多。
1 - 您可以在此处使用同步连接。一个缺点是您不会获得用于身份验证、重定向、缓存等的回调(同步连接的所有正常缺点。)另外,每个连接当然会阻塞一个线程一段时间,所以如果你正在做其中很多,那么您可能会同时阻塞几个线程,这很昂贵。
2 - 如果您的连接很简单并且您使用的是 iOS5,那么您可以使用此方法:
+ (void)sendAsynchronousRequest:(NSURLRequest *)request
queue:(NSOperationQueue*) queue
completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))
这将启动一个异步连接,然后允许您指定一个完成处理程序(用于成功或失败)和一个您希望在其上安排该块的 NSOperationQueue。
同样,您的缺点是无法获得身份验证、缓存等可能需要的回调。但至少您没有被正在运行的连接阻塞的线程。
3 - iOS5 的另一个选项是为所有委托回调设置队列:
- (void)setDelegateQueue:(NSOperationQueue*) queue NS_AVAILABLE(10_7, 5_0);
如果你使用它,那么所有的委托方法都将在你指定的任何 NSOperationQueue 的上下文中执行。所以这类似于选项 #2,希望您现在获得所有委托方法来处理身份验证、重定向等。
4 - 您可以设置自己的线程,专门控制这些线程来管理这些连接。在设置该线程时,您可以适当地配置一个运行循环。这在 iOS4 和 5 中可以正常工作,并且显然为您提供了您想要处理的所有委托回调
5 - 您可能会考虑异步连接处理的哪些部分真正干扰了您的 UI。通常,启动连接或接收委托回调并不那么昂贵。昂贵(或不确定)的成本通常在于您最终收集的数据的处理过程中。这里要问的问题是,您真的可以通过在某个队列上调度一个块来启动一个异步连接,该连接将立即断开并在另一个线程上执行它的操作,从而真正节省时间吗?
因此,您可以从主线程开始连接,并在主线程上接收所有委托回调,然后在这些委托方法的实现中启动您需要的任何昂贵的工作在其他队列或线程上做。
所以是这样的:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// go ahead and receive this message on the main thread
// but then turn around and fire off a block to do the real expensive work
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Parse the data we've been collecting
});
}
同样,这并不全面。有很多方法可以解决这个问题,具体取决于您在此处的具体需求。但我希望这些想法有所帮助。