[iOS]delegate

delegate很简单,就是将protocal方法声明好,然后将方法实现交由其delegate来实现,发送消息给delegate,delegate实现了protocal中的方法即在监听消息,就可以实现想要的操作了,多见于在不同view间传递数据。

Becoming the Delegate of a Framework Class

A framework class or any other class that implements delegation declares a delegate property and a protocol (usually a formal protocol). The protocol lists the required and optional methods that the delegate implements. For an instance of your class to function as the delegate of a framework object, it must do the following:

        如果是自定义的delegation,那么就要将object设置成delegate,这个可以通过编程或者interface builder来完成

  • Set your object as the delegate (by assigning it to the delegate property). You can do this programmatically or through Interface Builder.

    如果是正式的protocol,那么就要在类的定义时声明采用这个protocol

  • If the protocol is formal, declare that your class adopts the protocol in the class definition. For example:

    @interface MyControllerClass : UIViewController <UIAlertViewDelegate> {
  • Implement all required methods of the protocol and any optional methods that you want to participate in.

    执行需要的protocol方法

Implementing a Delegate for a Custom Class

To implement a delegate for your custom class, complete the following steps:

  • Declare the delegate accessor methods in your class header file.

    - (id)delegate;
    - (void)setDelegate:(id)newDelegate;
  • Implement the accessor methods. In a memory-managed program, to avoid retain cycles, the setter method should not retain or copy your delegate.

    - (id)delegate {
        return delegate;
    }
     
    - (void)setDelegate:(id)newDelegate {
        delegate = newDelegate;
    }

    In a garbage-collected environment, where retain cycles are not a problem, you should not make the delegate a weak reference (by using the __weak type modifier). For more on retain cycles, see Advanced Memory Management Programming Guide. For more on weak references in garbage collection, see “Garbage Collection for Cocoa Essentials” in Garbage Collection Programming Guide.

  • Declare a formal or informal protocol containing the programmatic interface for the delegate. Informal protocols are categories on the NSObject class. If you declare a formal protocol for your delegate, make sure you mark groups of optional methods with the @optional directive.

    “The Form of Delegation Messages” gives advice for naming your own delegation methods.

  • Before invoking a delegation method, make sure the delegate implements it by sending it a respondsToSelector: message.

  • 在调用代理方法前,必须确保给代理通过respondsToSelector:发送消息然后代理接到消息才可以执行相关的内容 (就是发送通知出去)

     

    - (void)someMethod {
        if ( [delegate respondsToSelector:@selector(operationShouldProceed)] ) {
            if ( [delegate operationShouldProceed] ) {
                // do something appropriate
            }
        }
    }

    The precaution is necessary only for optional methods in a formal protocol or methods of an informal protocol.

 

委托(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协议:

 

  1. @interface FirstViewController : UIViewController <UIActionSheetDelegate>  

 


 

在View中添加一个按钮用于触发这个ActionSheet,然后编写这个按钮的响应代码:

 

  1. - (IBAction)invokeActionSheet:(id)sender {  
  2.       
  3.     UIActionSheet *actionSheet = [[UIActionSheet alloc]  
  4.                                   initWithTitle:@"Delegate Example"  
  5.                                   delegate:self // telling this class(ViewController) to implement UIActionSheetDelegate  
  6.                                   cancelButtonTitle:@"Cancel"  
  7.                                   destructiveButtonTitle:@"Destruct"  
  8.                                   otherButtonTitles:@"Button 1",@"Button 2",nil];  
  9.       
  10.     [actionSheet showInView:self.tabBarController.view];  
  11.     [actionSheet release];  
  12. }  


注意,上面有一个很重要的设置就是参数中有个delegate:self,这个设置就是指明了UIActionSheet的代理为self, 也即FirstViewController。
然后在FirstViewController.m中实现UIActionSheetDelegate中的方法:

  1. #pragma mark --UIActionSheet delegate methods  
  2. - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {  
  3.     switch (buttonIndex) {  
  4.         case 0:  
  5.             self.myTextFromActionSheet.text = @"Action Destructed!";  
  6.             break;  
  7.         case 1:  
  8.             self.myTextFromActionSheet.text = @"Action Button 1 Clicked!";  
  9.             break;  
  10.         case 2:  
  11.             self.myTextFromActionSheet.text = @"Action Button 2 Clicked!";  
  12.             break;  
  13.         case 3:  
  14.             self.myTextFromActionSheet.text = @"Cancel Button Clicked!";  
  15.             break;  
  16.         default:  
  17.             break;  
  18.     }  
  19.       
  20. }  


上面的几步我们完成了对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:

 

  1. @protocol ChangeTextViewDelegate <NSObject>  
  2.   
  3. - (void) textEntered:(NSString*) text;  
  4.   
  5. @end  


和UIActionSheet类似,在ChangeTextViewController中我们也需要添加一个代理的声明:

  1. @property (assign, nonatomic) id<ChangeTextViewDelegate> delegate;  

 


3、我们还需要在ChangeTextViewController.xib中添加一个按钮save,当按下这个按钮会返回到second view中,并更新字符串。对save按钮的响应函数为:

  1. - (IBAction)saveButtonClicked:(id)sender {  
  2.     //Is anyone listening  
  3.     if([delegate respondsToSelector:@selector(textEntered:)])  
  4.     {  
  5.         //send the delegate function with the amount entered by the user  
  6.         [delegate textEntered:textEntered.text];  
  7.     }  
  8.       
  9.     [self dismissModalViewControllerAnimated:YES];  
  10. }  


 

 

[delegatetextEntered:textEntered.text];这句代码的含义就是ChangeTextViewController 通知代理,textEntered这个事件发生了,对textEntered这个消息的实现,即如何响应这个textEntered的事件由代理来实现。 在本例中,SecondViewController就是ChangeTextViewController对象的代理。所以,我们要对 SecondViewController做相应的设置使其满足代理的条件。首先,在SecondViewController.h中声明遵循协议 ChangeTextViewDelegate。然后编辑ChangeText按钮的响应函数- (IBAction)changeText:(id)sender;

 

  1. - (IBAction)changeText:(id)sender {  
  2.     ChangeTextViewController *CTViewController = [[ChangeTextViewController alloc] initWithNibName:@"ChangeTextViewController" bundle:nil];  
  3.     //Assign this class to the delegate of ChangeTextViewController,  
  4.     //remember to make thie ViewController confirm to protocol "ChangeTextViewDelegate"  
  5.     //which is delared in file ChangeTextViewController.h  
  6.     CTViewController.delegate = self;  
  7.     [self presentModalViewController:CTViewController animated:YES];  
  8. }  


注意,CTViewController.delegate = self;这句实现了SecondViewController成为ChangeTextViewController对象的代理。

本文对应的源代码下载:http://download.csdn.net/detail/lovefqing/4874331

 

例子程序详细解说:

1.》 formal delegate 即使用正式的delegate系统级别的

       步骤:

        在.h中首先声明要使用某个delegate,形式为:@interface FirstViewController : UIViewController <UIActionSheetDelegate> 这样就是声明要使用uiactionsheet的代理方法

        在.m中实现 UIActionSheetDelegate 中需要的以及必须的protocal方法

      #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;
              }

        }

2.》 informal / custom delegate 即使用非正式的 / 自定义的delegate

       步骤:

      在.h中定要实现的自己的protocal和方法

 

        @protocol ChangeTextViewDelegate <NSObject>

          - (void) textEntered:(NSString*) text;

        @end

        @interface ChangeTextViewController : UIViewController{
            IBOutlet UITextField *textEntered;
            id<ChangeTextViewDelegate> delegate;
          }

        @property (retain, nonatomic) IBOutlet UITextField *textEntered;
        @property (assign, nonatomic) id<ChangeTextViewDelegate> delegate;

        - (IBAction)cancelButtonClicked:(id)sender;
        - (IBAction)saveButtonClicked:(id)sender;

        @end

        在.m文件中给delegate发送消息来更改text内容

        - (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类中.h 声明要使用此protocal

      @interface SecondViewController : UIViewController<ChangeTextViewDelegate>

       在delegate类中.m实现protocal类中声明的方法,即为正在监听此事件

      - (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; //这句非常重要,这句实现了SecondViewController成为ChangeTextViewController对象的代理。
            [self presentModalViewController:CTViewController animated:YES];
        }

      #pragma mark --ChangeTextDelegate  实现了protocal方法textEntered即在监听消息,改变本界面中的text
        -(void) textEntered:(NSString *)text{
                self.myText.text = text;
       }

 调用顺序;delegate调出protocal界面,点击save响应protocal的save方法首先发送消息给delegate函数,然后调用delegate来改变delegate界面的内容,最后dissmiss当前protocal界面

就可以看到之前的delegate界面内容已经变化了。

 

posted @ 2013-09-09 15:40  如来藏  阅读(512)  评论(0编辑  收藏  举报