• Objective-c中的delegate浅析


    delegate初探

    在ios开发中,我们常常会用到类似例如以下的对话框:


    因此,例如以下这段代码我们也就非常熟悉了:

    - (IBAction)showSheet:(id)sender {
        UIActionSheet *actionSheet = [[UIActionSheet alloc]
                                      initWithTitle:@"title,nil时不显示"
                                      delegate:self
                                      cancelButtonTitle:@"取消"
                                      destructiveButtonTitle:@"确定"
                                      otherButtonTitles:@"第一项", @"第二项",nil];
        actionSheet.actionSheetStyle = UIActionSheetStyleBlackOpaque;
        [actionSheet showInView:self.view];
    }
    当中initWithTitle函数的第二个參数为delegate,那么是什么呢? 我们到它的头文件里看看。

    initWithTitle这个函数的声明例如以下 : 

    - (id)initWithTitle:(NSString *)title delegate:(id<UIActionSheetDelegate>)delegate cancelButtonTitle:(NSString *)cancelButtonTitle destructiveButtonTitle:(NSString *)destructiveButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION;
    是的,上面这个巨长无比的函数声明就是initWithTitile函数,oc这个语言本身给我的感觉就是繁杂。废话不多说,我们直接看到delegate參数的类型是id<UIActionSheetDelegate>。直接看UIActionSheetDelegate的声明:

    @protocol UIActionSheetDelegate <NSObject>
    @optional
    
    // Called when a button is clicked. The view will be automatically dismissed after this call returns
    - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex;
    
    // Called when we cancel a view (eg. the user clicks the Home button). This is not called when the user clicks the cancel button.
    // If not defined in the delegate, we simulate a click in the cancel button
    - (void)actionSheetCancel:(UIActionSheet *)actionSheet;
    
    - (void)willPresentActionSheet:(UIActionSheet *)actionSheet;  // before animation and showing view
    - (void)didPresentActionSheet:(UIActionSheet *)actionSheet;  // after animation
    
    - (void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex; // before animation and hiding view
    - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex;  // after animation
    
    @end
    能够看到UIActionSheetDelegate是一个普普通通的协议,在@optional以下有六个函数,这些函数都是可选实现的,每一个函数相应的是UIActionSheet中每一个button的点击事件处理。当然最后两个函数是依照索引来区分Button对象的。

    delagate的实现

    协议与delegate不是同一概念,协议是语言级别的特性,而delegate是借助协议来的实现的一种设计模式,事实上就是代理模式。通过注入

    代理对象实现对应的功能。

    事实上它的主要功能也就是实现回调,Java中的listener一样。

    以下以一个演示样例来说明 :

    // ButtonClickDelegate协议
    @protocol ButtonClickDelegate <NSObject>
    
    -(void) onClick: (id) sender ;
    
    @end
    
    
    // view的声明。实现了ButtonClickDelegate协议
    @interface UIView : NSObject    <ButtonClickDelegate >
    {
    @protected id<ButtonClickDelegate> clickDelegate ;
    }
    
    // 点击事件代理。因此UIView实现了ButtonClickDelegate协议,因此自己能够为自己代理。
    @property (nonatomic, strong) id<ButtonClickDelegate> clickDelegate ;
    // 点击view的触发函数
    -(void) performClick ;
    
    @end
    
    // view的实现
    @implementation UIView
    
    @synthesize clickDelegate ;
    
    // 默认的点击事件
    -(id) init
    {
        self = [super init] ;
        if ( self ) {
            clickDelegate = self ;
        }
        return self;
    }
    
    // 点击view的事件的默认处理
    -(void) onClick: (id) sender
    {
        NSLog(@"点击view的默认处理函数.") ;
    }
    
    // 点击事件
    -(void) performClick
    {
        [clickDelegate onClick: self ] ;
    }
    
    @end
    
    
    
    // ViewController声明, 实现了ButtonClickDelegate协议,能够作为UIView的代理
    @interface ViewController : NSObject <ButtonClickDelegate>
    @property (nonatomic, strong) UIView* parenView ;
    @end
    
    // ViewController实现
    @implementation ViewController
    
    -(void) onClick:(id)sender
    {
        NSLog(@"ViewController来实现点击事件") ;
    }
    
    @end
    
    main函数:

    // main
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            // view对象
            UIView* view = [[UIView alloc] init] ;
            [view performClick] ;
            
            // 构建一个ViewController对象
            ViewController* controller = [[ViewController alloc] init] ;
            view.clickDelegate = controller ;
            [view performClick] ;
            
        }
        return 0;
    }
    

    首先创建了一个UIView对象view, 然后调用performClick函数,此时view没有设置delegate,可是因为自己实现了ButtonClickDelegate协议,因此能够为自己代理该点击事件。然后我们创建了ViewController对象controller, 而且将该对象设置为view对象的delegate。 然后运行performClick函数,此时在performClick函数中

    会运行ViewController中的onClick函数。即controller代理了view的点击事件处理。输出结果例如以下 : 

    点击view的默认处理函数.
    ViewController来实现点击事件

    delegate与Java中的Listener

    delegate与Java中的Listener的功能大致是同样的,比方我们看看Android中一个button的点击事件的处理。

    	Button	mJumpButton = (Button) findViewById(R.id.button_jump);
    	mJumpButton.setOnClickListener(new OnClickListener() {
    
    			@Override
    			public void onClick(View v) {
    				Intent intent = new Intent(MainActivity.this,
    						SecondActivity.class);
    				startActivity(intent);
    			}
    		});

    当中的Button就相当于上文中的UIView,而其setOnClickListener就相当于delegate属性的设置方法。OnClickListener就扮演了上文中ButtonClickDelegate的角色,

    onClick方法更是如出一辙。事实上每一个平台大体上的设计思路也都是非常相近的,观察不同平台的对照实现更easy理解吧。


    delegate与id类型

    我们在声明一个delegate对象是的形式是例如以下这种 : 

    // 点击事件代理,因此UIView实现了ButtonClickDelegate协议。因此自己能够为自己代理。
    @property (nonatomic, strong) id<ButtonClickDelegate> clickDelegate ;

    注意这里的类型是id<ButtonClickDelegate>;这表明该delegate对象能够是随意类型,可是该类型必须实现ButtonClickDelegate协议也能够说成该类型必须採用正式协议ButtonClickDelegate。这个就非常像Java中的泛型。比如我们能够在Java中这样使用泛型,

    void setData(List<? extends Order> myorders) ;
    在setData函数中接受的參数为元素类型为Order子类的List集合,与id<ButtonClickDelegate>是不是又非常相似呢?

  • 相关阅读:
    effective C++
    bat取时间间隔
    bat设置windows计划任务
    listener.ora 与 tnsnames.ora
    route(windows)
    bat 数组实现
    非const引用参数传入不同类型编译不过的理解(拒绝将临时对象绑定为非const的引用的形参是有道理的)
    python no module named builtins
    Caffe使用新版本CUDA和CuDNN
    Ubuntu16.04安装vim8
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/7274129.html
Copyright © 2020-2023  润新知