GCD和异步NSURLConnection [英] GCD and async NSURLConnection

查看:70
本文介绍了GCD和异步NSURLConnection的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道如果我创建一个NSURLConnection(标准的异步),它将在同一个线程上回调。目前这是我的主线程。 (工作正常)。



但我现在使用相同的代码来做其他事情,我需要让我的UI保持活泼......



如果我这样做

  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^ {

/ *并且在这里,在某些NSURLConnection创建* /


});

..我的NSURLConnection可能已创建,但我的线程在url连接返回之前消失了吗?



我是GCD的新手。在我的url连接返回之前,如何让线程保持活动状态,或者有更好的方法可以做到这一点?

解决方案

所以问题实际上不是你的块运行的线程的生命周期,事实是这个特定的线程不会配置runloop并且正在运行以接收从连接返回的任何事件。



那你怎么解决这个问题?有不同的选择可供思考。我可以列出一些,我相信其他人会列出更多。



1 - 你可以在这里使用同步连接。一个缺点是你不会得到认证,重定向,缓存等的回调。(同步连接的所有常见缺点。)加上每个连接当然会阻塞一段时间的线程,所以如果你正在做很多这些你可能会同时阻止一些线程,这是昂贵的。



2 - 如果您的连接很简单,您正在使用iOS5然后您可以使用此方法:

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

这将启动一个异步连接,然后允许您指定一个完成处理程序(成功或失败)一个您希望在其上安排该块的NSOperationQueue。 / p>

同样,你有缺点获得您可能需要进行身份验证,缓存等的回调。但至少您没有被正在进行的连接阻止的线程。



3 - iOS5的另一个选项是为所有委托回调设置队列



- ( void)setDelegateQueue:(NSOperationQueue *)队列NS_AVAILABLE(10_7,5_0);



如果你使用它,那么所有的委托方法都将在您指定的任何NSOperationQueue的上下文中执行。所以这与选项#2类似,期望您现在可以获得所有委托方法来处理身份验证,重定向等。



4 - 您可以设置自己专门用于管理这些连接的线程。在设置该线程时,您可以适当地配置runloop。这在iOS4和5中可以正常工作,显然可以为你提供你想要处理的所有委托回调



5 - 你可能会想到异步连接处理的哪些部分真的干扰了您的UI。通常,启动连接或接收委托回调并不昂贵。昂贵(或不确定)的成本通常用于处理您最后收集的数据。这里要问的问题是你真的通过在某个队列上安排一个块来节省时间,只是为了启动一个异步连接,它会立即启动并在另一个线程上做它的事情吗?



所以你可以从主线程开始连接,并接收主线程上的所有委托回调,然后在你的那些委托方法的实现中触发你需要的任何昂贵的工作在其他一些队列或线程上做。



这样的事情:

   - (void)connectionDidFinishLoading: (NSURLConnection *)连接{
//继续在主线程
//上接收此消息,然后转身并触发一个块来执行真正昂贵的工作

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^ {

//解析我们收集的数据

});

}

同样,这并不全面。根据您的具体需求,有很多方法可以解决这个问题。但我希望这些想法有所帮助。


I know that if I create an NSURLConnection (standard async one), it will call back on the same thread. Currently this is on my main thread. (work fine too).

But i'm now using the same code for something else, and I need to keep my UI snappy....

If i do

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    /* and inside here, at some NSURLConnection is created */


});

.. is it possible that my NSURLConnection is created but my thread disappears before the url connection has returned?

I'm new to GCD. How would one keep the thread alive until my url connection returned, or is there a better way I could be doing this?

解决方案

So really the issue isn't the lifetime of the thread on which your block runs, it's the fact that this particular thread is not going to have a runloop configured and running to receive any of the events coming back from the connection.

So how do you solve this? There are different options to think about. I can list a few, and I'm sure others will list more.

1 - You could use a synchronous connection here. One disadvantage is that you won't get callbacks for authentication, redirection, caching, etc. (All the normal disadvantages of synchronous connections.) Plus each connection will of course block a thread for some period of time, so if you're doing a lot of these then you could potentially have a few threads blocked at once, which is expensive.

2 - If your connection is simple and you are using iOS5 then you can use this method:

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

This will start an asynchronous connection and then allow you to specify a completion handler (for success or failure) and a NSOperationQueue on which you want that block to be scheduled.

Again, you have the disadvantages of not getting the callbacks you might need for authentication, caching, etc. But at least you don't have threads hanging around blocked by connections that are in flight.

3 - Another option for iOS5 is to set the queue for all delegate callbacks:

- (void)setDelegateQueue:(NSOperationQueue*) queue NS_AVAILABLE(10_7, 5_0);

If you use this, then all of the delegate methods will be executed in the context of whatever NSOperationQueue you specify. So this is similar to option #2, expect that you get all of the delegate methods now to handle authentication, redirection, etc.

4 - You could set up your own thread that you control specifically for managing these connections. And in setting up that thread, you configure a runloop appropriately. This would work fine in iOS4 and 5 and obviously gives you all of the delegate callbacks that you want to handle

5 - You might think about what parts of your asynchronous connection handling are really interfering with your UI. Typically kicking off the connection or receiving delegate callbacks are not that expensive. The expensive (or indeterminate) cost is often in the processing of the data that you collect at the end. The question to ask here is are you really saving time by scheduling a block on some queue just to start an asynchronous connection that will go off immediately and do its thing on another thread anyway?

So you could just start the connection from the main thread, and receive all of the delegate callbacks on the main thread, and then in your implementation of those delegate methods fire off whatever expensive work you need to do on some other queue or thread.

So something like this:

- (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

        });

    }

Again, this is not comprehensive. There are many ways to handle this, depending on your specific needs here. But I hope these thoughts help.

这篇关于GCD和异步NSURLConnection的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆