GCD和asynchronousNSURLConnection

我知道如果我创build一个NSURLConnection(标准的asynchronous),它会callback在同一个线程。 目前这是在我的主线上。 (工作也很好)。

但我现在使用相同的代码的其他东西,我需要保持我的UI snappy ….

如果我做

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ /* and inside here, at some NSURLConnection is created */ }); 

..是否有可能是我的NSURLConnection创build,但我的线程在url连接返回之前消失?

我是GCD的新手。 如何保持线程活着,直到我的url连接返回,还是有更好的办法,我可以做到这一点?

所以真正的问题不在于你的块运行的线程的生命周期,这是这个特定的线程不会有一个runloopconfiguration和运行,以接收从连接返回的任何事件。

那么你如何解决这个问题呢? 有不同的select来思考。 我可以列举一些,我相信别人会列出更多。

1 – 你可以在这里使用同步连接。 一个缺点是,你不会得到authentication,redirect,caching等callback(同步连接的所有正常缺点)。加上每个连接当然会阻塞一段时间的线程,所以如果你在做很多这些,那么你可能会有一些线程一次被阻塞,这是昂贵的。

2 – 如果你的连接很简单,你使用的是iOS5,那么你可以使用这个方法:

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

这将启动一个asynchronous连接,然后允许你指定一个完成处理程序(用于成功或失败) 一个NSOperationQueue,你希望这个块被调度。

同样,你有缺点,没有得到你可能需要进行身份validation,caching等callback。但至less你没有线程挂在四处被阻塞的飞行中的连接。

3 – iOS5的另一个选项是为所有委托callback设置队列:

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

如果你使用这个,那么所有的委托方法都会在你指定的NSOperationQueue的上下文中执行。 所以这和选项#2类似,希望你现在可以得到所有的委托方法来处理authentication,redirect等。

4 – 您可以设置自己的线程,专门用于pipe理这些连接。 在设置该线程时,可以适当地configurationrunloop。 这将在iOS4和5中正常工作,显然会给你所有你想要处理的委托callback

5 – 您可能会考虑asynchronous连接处理的哪些部分会干扰您的用户界面。 通常踢开连接或接收委托callback并不昂贵。 昂贵的(或不确定的)成本往往是在处理你最后收集的数据。 这里要问的问题是,通过在某个队列上安排一个块来节省时间,只是为了启动一个asynchronous连接,它将立即closures,并在另一个线程上完成它的工作。

所以你可以从主线程开始连接,并在主线程上接收所有的委托callback,然后在你实现这些委托方法的时候,就可以在任何其他队列或者线程上进行昂贵的工作。

所以像这样的东西:

 - (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 }); } 

再次,这不是全面的。 有很多方法来处理这个问题,这取决于你的具体需求。 但是我希望这些想法能够帮上忙

就像为什么你的线程正在消失(以及为了将来参考)一样,NSURLConnection需要一个runloop。 如果你添加了

 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]]; 

你会看到连接正常运行,线程不会消失,直到连接完成。

首先,你的块和你在其中使用的每个variables都将被复制到GCD,所以代码不会在你的线程上执行,而是在全局队列上执行。

如果您想要在主线程上获取数据,则可以在获取数据后嵌套asynchronous调用:

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"www.stackoverflow.com"]]; NSURLResponse *response; NSError *error; NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; if (error) { // handle error return; } dispatch_async(dispatch_get_main_queue(), ^{ // do something with the data }); }); 

但为什么不使用NSURLConnection的内置asynchronous支持? 你需要一个NSOperationQueue,但是如果你正在做很多的networking抓取,那么无论如何,

 NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"www.stackoverflow.com"]]; [NSURLConnection sendAsynchronousRequest:request queue:self.queue // created at class init completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){ // do something with data or handle error }]; 

就个人而言,我使用像AFNetworking或ASIHTTPRequest这样的库来使networking更加容易,这两个块都支持块(前者利用GCD并且更现代一点)。

 dispatch_queue_t queue = dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ [btnCreateSmartList setEnabled:NO]; [dbSingleton() createEditableCopyOfDatabaseIfNeeded]; [dbSingleton() insert_SMART_PlaceList:txtListName.text :0:txtTravelType.text: [strgDuration intValue]:strgTemprature:Strgender:bimgdt]; [self Save_items]; //*********navigate new dispatch_async(dispatch_get_main_queue(), ^{ [activityIndicator stopAnimating]; [self performSelector:@selector(gonext_screen) withObject:nil afterDelay:0.0]; }); }); 
Interesting Posts