我知道如果我创建一个NSURLConnection(标准的异步),它将在同一个线程上回调。目前这是我的主线程。 (工作也很好)。
但我现在正在使用相同的代码来处理其他事情,我需要让我的UI保持活泼......
如果我这样做
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
/* and inside here, at some NSURLConnection is created */
});
..是否有可能创建了我的NSURLConnection但我的线程在url连接返回之前消失了?
我是GCD的新手。在我的url连接返回之前,如何让线程保持活动状态,或者有更好的方法可以做到这一点?
答案 0 :(得分:37)
所以问题实际上不是你的块运行的线程的生命周期,事实上这个特定的线程不会配置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 - 您可以设置自己专门用于管理这些连接的线程。在设置该线程时,您可以适当地配置runloop。这在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
});
}
同样,这并不全面。根据您的具体需求,有很多方法可以解决这个问题。但我希望这些想法有所帮助。
答案 1 :(得分:9)
作为对你的线程为什么会消失(以及将来参考)的答案,NSURLConnection需要一个runloop。如果您已添加
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
您会看到连接正常运行且线程不会消失,直到连接完成。
答案 2 :(得分:3)
首先,您的块和您在其中使用的每个变量都将被复制到GCD,因此代码不会在您的线程上执行,而是在全局队列中执行。
如果要在主线程上恢复数据,可以在获取数据后嵌套异步调用:
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的内置异步支持?您需要一个NSOperationQueue,但如果您正在进行大量的网络提取,那么无论如何都是这样:
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这样的库来使网络变得更加容易,它们都支持块(前者使用GCD并且更加现代化)。
答案 3 :(得分:0)
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];
});
});