標籤:
寫在前面
上一篇學習筆記中簡單介紹了通過目標-動作對實現回調操作:建立兩個對象timer和logger,將logger設定為timer的目標,timer定時調用logger的sayOuch函數。在這個例子中,timer的任務比較簡單,只完成一項任務:在指定的時刻觸發事件。在這種情況下,適合選擇目標-動作來實現回調,但這種方式不適合要發送多個回調的情況。
輔助對象
輔助對象是另一種實現回調的方式。在應用開始等待前,要求當等待的特定事件發生時,向遵守相應協議的輔助對象發送訊息。委派物件和資料來源是常見的輔助對象。
案例
假定我們建立一個NSURLConnection對象並從一個給定的url中擷取資料,然後等待回調。回呼函數被觸發的時機包括:獲得資料、資料擷取完成、擷取資料失敗等。
可見,如果只是簡單的目標-動作隊機制,無法實現這些複雜的回調。因此,我們為NSURLConnection對象設定一個輔助對象,這個輔助對象專門負責處理特定事件發生之後的事情,也就是說,當特定的事件發生後,NSURLConnection對象會向輔助對象發送訊息。這些訊息包含在一套協議中。協議和介面概念有些相似,協議就是一組方法的聲明,遵循相應協議的類必須實現協議中的方法(可以只實現部分方法)。
我們假定讓Logger類型的對象成為NSURLConnection對象的輔助對象,也就是說,將Logger對象賦給NSURLConne對象的成員變數delegate。Logger類必須實現NSURLConnection協議中的部分活全部方法。關係圖如下:
首先更改Logger類的代碼,由於要接收資料,因此為Logger類添加一個NSMutableData類型的屬性,如下:
Logger.h
@property NSMutableData *incomingData;
然後在Logger.m中實現協議中的部分方法
//收到一定位元組數的資料後會被調用- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ NSLog(@"received %lu bytes", [data length]); if (!self.incomingData) { self.incomingData = [[NSMutableData alloc] init]; } [self.incomingData appendData: data];}//最後一部分資料處理完畢後,會被調用- (void)connectionDidFinishLoading:(NSURLConnection *)connection{ NSLog(@"Got it all!"); NSString *string = [[NSString alloc] initWithData:self.incomingData encoding:NSUTF8StringEncoding]; self.incomingData = nil; NSLog(@"string has %lu characters", [string length]); NSLog(@"The whole string is %@", string);}//擷取資料失敗時,會被調用- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{ NSLog(@"connection failed: %@",[error localizedDescription]); self.incomingData = nil;}
在main函數中建立Logger對象和NSURLConnection,並將前者設定為後者的輔助對象:
Logger *logger = [[Logger alloc] init]; NSURL *url = [NSURL URLWithString:@"http://www.cnblogs.com/scut-linmaojiang/p/iOS-huidiao-y.html"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; NSURLConnection *fetchConn = [[NSURLConnection alloc] initWithRequest:request delegate:logger startImmediately:YES];
如上所示,當NSURLConnection對象fetchConn從指定url擷取資料時,將logger對象設定為它的輔助對象,也就是將logger作為fetchConn對象的委託。fetchCon擷取資料過程中的各種狀態會觸發logger執行對應狀態下的方法。利用斷點設定,我們可以知道正常情況下,logger執行回呼函數的順序為:
1、接收到資料,執行
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
運行如下:
2、最後一部分資料處理完畢,執行
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
運行如下:
...
url是上一篇筆記的地址,擷取到的資料是以html格式顯示的
如果電腦處理斷網狀態,那麼fetchConn將無法擷取到資料,此時logger將執行下面的回呼函數
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
運行如下:
總結
對比目標-動作對機制和輔助對象機制這兩種實現回調的方式可知,當某個對象只提供了一個回呼函數時,使用目標-動作對較為合適。而當某個對象要提供多個回呼函數,也就說要接收多個回調資訊時,使用遵循相應協議的輔助對象較為合理。
iOS學習筆記之回調(二)