2011-11-22 78 views
8

我怎樣才能讓NSURLConnection從不同的線程調用它的委託方法,而不是主線程。我正在嘗試調度scheduleInRunLoop:forMode:但似乎沒有做我想做的事情。iOS,NSURLConnection:在不同線程上委託回調?

我必須下載一個大文件,它會頻繁地中斷主線程,以至於一些正在發生的渲染開始變得波濤洶涌。

NSURLRequest * request = [NSURLRequest requestWithURL:url]; 
NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; 
NSRunLoop * loop = [NSRunLoop currentRunLoop]; 
NSLog(@"loop mode: %@",[loop currentMode]); 
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; 
[connection start]; 

我沒有看到太多的其他東西是「模式」只有兩種模式記錄在案,所以沒有太多真正的測試。

任何想法?

感謝

回答

6

有幾種選擇:

  1. 在你實現的委託方法,利用dispatch_async
  2. 在後臺線程上啓動連接計劃。

你可以做後者是這樣的:

// all the setup comes here 
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    NSRunLoop *loop = [NSRunLoop currentRunLoop]; 
    [connection scheduleInRunLoop:loop forMode:NSRunLoopCommonModes]; 
    [loop run]; // make sure that you have a running run-loop. 
}); 

如果您想對您正在運行的線程的保證,適當更換呼叫dispatch_get_global_queue()

+1

不會保留隊列運行的線程嗎?所以,我這樣稱呼一次,線程一直存在。我再次調用這個函數,因爲GCD決定隊列運行的線程,然後可能還有另一個線程在等待......所以,一旦工作完成後線程無法正常工作,全球隊列?另外,你的意思是「如果你想保證你正在運行哪個線程,請將調用適當地替換爲dispatch_get_global_queue()。」?你如何通過GCD定位一個線程? – zumzum

0

如果你真的需要做的下載在一個新的線程,它可能更容易detachNewThreadSelector:toTarget:withObject:,建立(和破壞)的NSAutoreleasePool,然後用同步選擇像NSDatadataWithContentsOfURL:之一。這不會使用異步NSURLConnectionDelegate

因爲這個調用是同步的,所以直到文件被下載後纔會返回,這會阻塞主線程,但是因爲你在新線程中,它不會。請注意,這通常是令人沮喪的行爲。主線程中是否有其他代碼可以優化?

+0

試過了。我正在下載的文件很大,所以我需要將它寫入磁盤,因爲它正在進入。 – gngrwzrd

0

NSURLConnection已經以異步方式從主線程下載。如果我理解你的問題,你希望委託消息在主線程以外的線程上發送?你不能這樣做,因爲你不能修改NSURLConnection的內部實現。我可以想出兩種方法來模擬這一點。

  1. 創建的NSURLConnection(例如MyURLConnection)一個sublcass其自己指定爲自己的委託。請注意,這會產生故意的保留週期,因此請小心。 MyURLConnection應定義支持NSURLConnectionDelegate的新的delegate。我們稱之爲finalDelegate。當MyURLConnection處理它自己的委託消息時,可以將它們轉發或發送到finalDelegate,而不管你喜歡什麼線索。

  2. 與選項#1類似但沒有子類。在主線程上處理NSURLConnection委託方法,並將它們轉發/分派給您喜歡的任何線程。

主要的區別是,如果你想要一個可重複使用的子類,這樣的行爲或它是一個實施。

編輯:如何在後臺

運行的代碼。如果你要在後臺處理的響應添加建議我要麼使用操作或大中央調度。不需要搞亂運行循環和創建線程。看看蘋果的Concurrency Programming Guide

2

如果你想在一個單獨的線程進行下載,我敢肯定這是你要找的機器人......

- (void) dispatchRequest{ 
    self->finished = NO; 
    NSMutableURLRequest* request = //Formulate your request 
    NSThread* download_thread = [[NSThread alloc] initWithTarget:self selector:@selector(downloadThreadLoop:) object:request]; 
    [download_thread start]; 
} 
- (void) downloadThreadLoop:(NSMutableURLRequest*) request{ 

    NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; 

    while(!self->finished]){ 
     //This line below is the magic! 
     [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 
    } 
} 

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{ 
    //... 
} 

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ 
    //... 
} 

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{ 
    //... 
} 

- (void)connectionDidFinishLoading:(NSURLConnection *)connection{ 
    //... 
    self->finished = YES; 
} 
+0

你有一個錯字:NSMubaleURLRequest,應該是NSMutableURLRequest – Borzh

+0

@Borzh,謝謝! – Brooks

相關問題