可以有兩個辦法讓NSURLConnection在子線程中運行,即將NSURLConnection加入到run loop或者NSOperationQueue中去運行。
前面提到可以將NSTimer手動加入NSRunLoop,Cocoa庫也為其它一些類提供了可以手動加入NSRunLoop的方法,這些類有NSPort、NSStream、NSURLConnection、NSNetServices,方法都是[scheduleInRunLoop:forMode:]形式。我暫時只介紹下最常用的NSURLConnection類,看看如何把NSURLConnection的網絡下載加入到其它線程的run loop去運行。
如果NSURLConnection是在主線程中啟動的,實際上它就在主線程中運行 -- 並非啟動的另外的線程,但又具備異步運行的特性,這個確實是run loop的巧妙所在。如果對run loop有了初步的了解和概念后,實際上就能明白NSURLConnection的運行,實際也是需要當前線程具備run loop。
- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; //將加入指定的run loop中運行,必須保證這時NSURLConnection不能啟動,否則不起作用了
- (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; //將取消在指定run loop中的運行,實際上就會停止NSURLConnection的運行
下面是如何在其它線程中運行NSURLConnection的主要實現代碼:
NSRunLoop *runloop; //global
[self performSelectorInBackground:@selector(thread) withObject:nil]; //啟動包含run loop的線程
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; //注意這時不能先啟動NSURLConnection
[conn scheduleInRunLoop:runloop forMode:NSRunLoopCommonModes]; //指定在上面啟動的線程中運行NSURLConnection
[conn start]; //啟動NSURLConnection
- (void)thread
{
runloop = [NSRunLoop currentRunLoop]; //設置為當前線程的run loop值
while (condition)
{
[runloop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; //啟動run loop
}
}
將NSURLConnection加入到NSOperationQueue中去運行的方式基本類似:
NSOperationQueue *queue = [[NSOperationQueuealloc] init];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[conn setDelegateQueue:queue];
[conn start];