iOS設計模式——委託(delegate)

委託(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(nonatomicassign)id<UIActionSheetDelegate> delegate;   // weak reference

通常格式爲@property(nonatomicassign)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


若本文有任何錯誤之處,歡迎拍磚指正,共同進步,謝謝!




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章