2011年2月20日 星期日

NSURLConnection 

在預設的情況下,一個 iPhone App 只有一條執行緒(Thread),簡單的說就是同一時間只能做一件事,所以當你用 NSData 或 NSString 的 initWithContentsOfURL 的方法來載入網頁資料時,整個程式就會停在那裡,直到網頁資料都下載完了後,才會繼續執行下一行的程式碼。繼然程式停在那不動,當然你不論怎麼加上其它的動畫或View都不會有作用,這就是我昨天一直失敗的原因。

所以有兩種方式來解決這個問題,一是自己開 Thread 來用時做好幾件事,二是使用委託處理的方式,把要做的事情委託出去,等事情做完後,被委託的人會通知你事情已經處理完了。這也就是 iOS 一直強調的 delgate model。

自己開 Thread 並不適合用在 iT邦幫忙 App 裡,因為我必需要知道網頁資料何時會下載完畢,等下載完畢後,再把載入等待畫面給移除。所以我需要找到一個能幫我下載網頁資料,然後下載完後能通知我的一個類別,那個就是 - NSURLConnection。

NSURLConnection 宣告使用的程式碼如下:

  1. NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://ithelp.ithome.com.tw/?tab=share"]];  
  2. [NSURLConnection connectionWithRequest:request delegate:self];  


它需要兩個參數,一個是 NSURLRequest 物件,另一個是 delegate 物件。上面的程式碼把 delegate 指向自己(self),也就是目前所在的類別來接受 NSURLConnect 的事件。最重要的有四個事件處理的方法:
  1. //是否收到網站的回應  
  2. - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {  
  3.     [htmlData setLength:0];  
  4. }  
  5.   
  6. //收到網站傳回的資料  
  7. - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {  
  8.     [htmlData appendData:data];  
  9. }  
  10.   
  11. //網頁資料下載完畢  
  12. - (void)connectionDidFinishLoading:(NSURLConnection *)connection {  
  13.     NSLog(@"Succeeded! Received %d bytes of data",[htmlData length]);  
  14.     NSLog(@"%@", [[NSString alloc] initWithData:htmlData encoding:NSUTF8StringEncoding]);  
  15. }  
  16.   
  17. //網路連線錯誤  
  18. - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {  
  19.     [connection release];  
  20.      NSLog(@"Connection failed! Error - %@ %@",  
  21.           [error localizedDescription],  
  22.           [[error userInfo] objectForKey:NSErrorFailingURLStringKey]);      
  23. }  


htmlData 是個 NSMutableData 的物件,當 NSURLConnect 連上網站時,我先把 htmlData 清空準備來接收網頁資料。NSURLConnection 會把網頁資料一段一段下載回來,每當下載一部份時,didReceiveData 方法會收到通知,這時我把資頁資料給存放進 htmlData 物件裡。等到全部下載回來後,會呼叫 connectionDidFinishLoading 方法,這時我就把網頁的資料給印出來...

當下載的過程中發生錯誤時,會呼叫 didFailWithError 的方法,這時我會印出錯誤訊息,看看發生了什麼事。

沒有留言:

張貼留言