delegate协议

10 8月

delegate设计模式在IOS中很常见,例如UITabBarController内部声明了delegate协议:

shouldSelectViewController:点击时询问是否切换UIViewController?如果返回NO就不切换tab。
didSelectViewController:切换完UIViewController后,可以在里面实现视频自动播放,自动刷新等动作。

@property(nullable, nonatomic,weak) id delegate;    // delegate属性

@protocol UITabBarControllerDelegate;               // delegate方法
@optional
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController NS_AVAILABLE_IOS(3_0);
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController;
...
@end

使用delegate

要使用delegate也有板式套路:

  1. 声明要实现的delegate
  2. 设置self为delegate的接收者,例如:tabBar.delegate = self;
  3. 实现delegate中的方法
@interface AppDelegate ()<UITabBarControllerDelegate>    // 实现delegate第一步:声明要实现的delegate
...
tabBarC.delegate = self;                                 // 实现delegate第二步:设置self为delegate的接收者
...
// 实现delegate第三步:实现delegate中的方法
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController NS_AVAILABLE_IOS(3_0) {
    NSLog(@"should select");
    return YES;
}
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
    NSLog(@"did select");
}

设计delegate

你也可以自己设计delegate,例如点击view里的按钮,在外层view里出现弹窗,就可以使用delegate设计模式。

内层view.h里声明delegate:

@protocol TestTableViewCellDelegate  // 自定义 delegate
-(void)tableViewCell:(UITableViewCell *)tableViewCell clickDeleteButton:(UIButton *)deleteButton;   // 自定义方法,两个参数cell和button
@end

@interface TestTableViewCell : UITableViewCell
@property(nonatomic, weak, readwrite) id delegate; // cell 拥有一个自定义的 delegate
@end

内层view.m里调用delegate:

-(void) deleteButtonClick {
    // 因为该方法不是 required 的,所以要判断一下是否已经实现了这个方法
    // 如果实现了该方法,就传入参数调用该方法
    if(self.delegate && [self.delegate respondsToSelector:@selector(tableViewCell:clickDeleteButton:)]) {
        [self.delegate tableViewCell:self clickDeleteButton:self.deleteButton];  // 调用delegate方法,将内层cell和button传给外层
    }
}

外层Controller中实现delegate的方法

@interface ViewController ()<TestTableViewCellDelegate>
@end

-(void)tableViewCell:(UITableViewCell *)tableViewCell clickDeleteButton:(UIButton *)deleteButton {
    ... // 当内层view点击按钮时,外层就能收到消息,这里能拿到内层view传来的参数 cell 和 button
}

block和delegate的区别

delegate运行成本低,block的运行成本高。因为block出栈需要将使用的数据从栈内存拷贝到堆内存,当然对象的话就是计数+1,使用完或者block置nil后才消除。delegate只是保存了一个对象指针,直接回调,没有额外消耗。就像C的函数指针,只多做了一个查表动作。

这也是为什么block用copy关键字的原因。block在没有使用外部变量时,内存存在全局区,当block在使用外部变量的时候,内存是存在于栈区,当block copy之后,是存在堆区的。存在于栈区的特点是对象随时有可能被销毁,一旦销毁在调用的时候,就会造成系统的崩溃。所以block要用copy关键字。

delegate更适用于多个回调方法(3个以上),block则适用于1,2个回调时。

发表评论

邮箱地址不会被公开。 必填项已用*标注