上一篇學習筆記中簡單介紹了通過目標-動作對實現回調操作:創建兩個對象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
運行截圖如下:
對比目標-動作對機制和輔助對象機制這兩種實現回調的方式可知,當某個對象只提供了一個回調函數時,使用目標-動作對較為合適。而當某個對象要提供多個回調函數,也就說要接收多個回調信息時,使用遵循相應協議的輔助對象較為合理。