委託(delegate)也叫代理是iOS開發中常用的設計模式。我們藉助於protocol(參考博文:objective-c協議(protocol))可以很方便的實現這種設計模式。
什麼是代理?
蘋果的官方文檔給了很清晰的解釋:
Delegation is a simple and powerful pattern in which one object in a program acts on behalf of, or in coordination with, another
object. The delegating object keeps a reference to the other object—the delegate—and at the appropriate time sends a message to it. The message informs the delegate of an event that the delegating object is about to handle or has just handled. The delegate
may respond to the message by updating the appearance or state of itself or other objects in the application, and in some cases it can return a value that affects how an impending event is handled. The main value of delegation is that it allows you to easily
customize the behavior of several objects in one central object.
意譯一下就是:代理是一種簡單而功能強大的設計模式,這種模式用於一個對象“代表”另外一個對象和程式中其他的對象進行互動。 主對象(這裡指的是delegating object)中維護一個代理(delegate)的引用並且在合適的時候向這個代理髮送訊息。這個訊息通知“代理”主對象即將處理或是已經處理完了某一個事件。這個代理可以通過更新自己或是其它對象的UI介面或是其它狀態來響應主對象所發送過來的這個事件的訊息。或是在某些情況下能返回一個值來影響其它即將發生的事件該如何來處理。代理的主要價值是它可以讓你容易的定製各種對象的行為。注意這裡的代理是個名詞,它本身是一個對象,這個對象是專門代表被代理對象來和程式中其他對象打交道的。
Cocoa中的代理
Cocoa Touch架構裡大量使用了代理這種設計模式,在每個UI控制項類裡面都聲明了一個類型為id的delegate或是dataSource,查看Cocoa的標頭檔可以發現很多如下的屬性:
@property(nonatomic, assign)id<UIActionSheetDelegate> delegate; // weak reference
通常格式為@property(nonatomic, assign)id<protocol_name> delegate; 即這個代理要遵循某一個協議,也就是說只有遵循了這個協議的類對象才具備代理資格。這同時也要求了代理類必須在標頭檔中聲明遵循這個protocol_name協議並實現其中的@required方法,@optional的方法是可選的。
以UIActionSheet為例,我們定義一個View,當點擊這個View中的某一個按鈕時觸發UIActionSheet, 當使用者對UIActionSheet完成了某一項操作,比如Destruct按鈕被按下,或是cancel按鈕被按下,UIActionSheet會發送訊息給delegate,由delegate完成對使用者操作的響應,比如列印一個字串到螢幕上。圖示說明如下:
首先,我們建立一個基於tab的工程,在FirstViewController.h中添加代碼,使這個類遵循UIActionSheetDelegate協議:
@interface FirstViewController : UIViewController <UIActionSheetDelegate>
在View中添加一個按鈕用於觸發這個ActionSheet,然後編寫這個按鈕的響應代碼:
- (IBAction)invokeActionSheet:(id)sender { UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"Delegate Example" delegate:self // telling this class(ViewController) to implement UIActionSheetDelegate cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Destruct" otherButtonTitles:@"Button 1",@"Button 2",nil]; [actionSheet showInView:self.tabBarController.view]; [actionSheet release];}
注意,上面有一個很重要的設定就是參數中有個delegate:self,這個設定就是指明了UIActionSheet的代理為self, 也即FirstViewController。
然後在FirstViewController.m中實現UIActionSheetDelegate中的方法:
#pragma mark --UIActionSheet delegate methods- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { switch (buttonIndex) { case 0: self.myTextFromActionSheet.text = @"Action Destructed!"; break; case 1: self.myTextFromActionSheet.text = @"Action Button 1 Clicked!"; break; case 2: self.myTextFromActionSheet.text = @"Action Button 2 Clicked!"; break; case 3: self.myTextFromActionSheet.text = @"Cancel Button Clicked!"; break; default: break; } }
上面的幾步我們完成了對Cocoa中UIActionSheet已有代理的運用。然而我們很多時候需要自己編寫定製的代理,該如何?呢?
自訂代理
我們要做的是,建立一個view,自訂一個代理實現更新這個view中的字串。上面我們已經建立好了一個tab工程,借用裡面的second view。我們拖一個按鈕到上面命名為ChangeText,響應函數為- (IBAction)changeText:(id)sender;點擊這個按鈕進入一個modal view 名為ChangeTextView,我們在ChangeTextView中輸入一個字串並在退出這個view後把這個字串更新到second
view上面。如何?modal view和second view之間的資料傳遞呢?那就是代理!誰的代理?ChangeTextView的代理!因為我們直接在ChangeTextView中輸入資料,需要由代理把輸入的字串反饋到second view上面去。
1、建立一個新的類ChangeTextViewController,並建立相應的xib檔案。
2、在ChangeTextViewController.h中聲明一個協議ChangeTextViewDelegate:
@protocol ChangeTextViewDelegate <NSObject>- (void) textEntered:(NSString*) text;@end
和UIActionSheet類似,在ChangeTextViewController中我們也需要添加一個代理的聲明:
@property (assign, nonatomic) id<ChangeTextViewDelegate> delegate;
3、我們還需要在ChangeTextViewController.xib中添加一個按鈕save,當按下這個按鈕會返回到second view中,並更新字串。對save按鈕的響應函數為:
- (IBAction)saveButtonClicked:(id)sender { //Is anyone listening if([delegate respondsToSelector:@selector(textEntered:)]) { //send the delegate function with the amount entered by the user [delegate textEntered:textEntered.text]; } [self dismissModalViewControllerAnimated:YES];}
[delegate textEntered:textEntered.text];這句代碼的含義就是ChangeTextViewController通知代理,textEntered這個事件發生了,對textEntered這個訊息的實現,即如何響應這個textEntered的事件由代理來實現。在本例中,SecondViewController就是ChangeTextViewController對象的代理。所以,我們要對SecondViewController做相應的設定使其滿足代理的條件。首先,在SecondViewController.h中聲明遵循協議ChangeTextViewDelegate。然後編輯ChangeText按鈕的響應函數-
(IBAction)changeText:(id)sender;
- (IBAction)changeText:(id)sender { ChangeTextViewController *CTViewController = [[ChangeTextViewController alloc] initWithNibName:@"ChangeTextViewController" bundle:nil]; //Assign this class to the delegate of ChangeTextViewController, //remember to make thie ViewController confirm to protocol "ChangeTextViewDelegate" //which is delared in file ChangeTextViewController.h CTViewController.delegate = self; [self presentModalViewController:CTViewController animated:YES];}
注意,CTViewController.delegate = self;這句實現了SecondViewController成為ChangeTextViewController對象的代理。
本文對應的原始碼下載:http://download.csdn.net/detail/lovefqing/4874331
若本文有任何錯誤之處,歡迎拍磚指正,共同進步,謝謝!