iOS 代理和block

Source

iOS 代理和block

做iOS三年了,平时开发过程中经常用到代理和block,两者即有相同的作用——都可以实现回调的作用,下面对两着做一些总结和对比。

代理

示例:有对象A:视图控制器、对象B:A的子控件TableView
·A是代理对象,B是被代理对象
·A要引用B
·A需要遵守协议,并且实现协议里面规定的方法
·B通过委托方法通知

Block

在iOS中block有三种
1.全局的静态block,不访问任何外部变量,执行完即回收

 ^{
        NSLog(@"Hello World!");
    }();

2.保存在栈中的 block,当函数返回时会被销毁,和第一种的区别就是调用了外部变量。

 //UIView动画
    [UIView animateWithDuration:3 animations:^{
        self.view.backgroundColor = [UIColor redColor];
    }];

3.保存在堆中的 block,当引用计数为 0 时会被销毁。例如按钮的点击事件,一直存在,即使执行过,也不销毁,因为按钮还可能被点击,持有按钮的View被销毁,它才会被销毁。

#import <UIKit/UIKit.h>

typedef void(^ButtonClickBlcok)();
 
@interface TestView : UIView
 
@property (nonatomic, copy) ButtonClickBlcok buttonClickBlcok;
 
@end
#import "TestView.h"
 
@implementation TestView
 
- (IBAction)buttonClick:(id)sender {
    
    if (self.buttonClickBlcok) {
        self.buttonClickBlcok();
    }
}
@end

示例:有对象A、B。B产生事件,A响应事件。
·B回调block,A传递block
·B需要定义block并且有一个block属性(定义block属性时需要用copy)
·A接收到事件传递block时,block里面的具体操作在这里定义,但在传递时不会执行,执行是在B回调block时block执行
定义block需要用关键字“copy”的原因:
Block存储在栈区,栈区的特性是当一个方法运行完成之后里面的内存就会释放掉,如果block被释放,那么后面回调就会遇到问题,所以要把block复制到堆区来存储。所以用copy把整个block内容拷贝过来并且在堆区新建一块空间来存储block。
造成循环引用的原因:
为了blcok不被系统回收,所以我们用copy关键字修饰,实行强引用。block对捕获的变量也都是强引用,所以就会造成循环引用。
···
__weak ViewController *weakSelf = self;
_testBlock = ^{

      //引发循环引用
      NSLog(@"%@", self);
      
    //防止循环引用
    NSLog(@"%@", weakSelf);
};

···

总结:
1.代理更注重过程信息的传输:比如发起一个网络请求,可能想要知道此时请求是否已经开始、是否收到了数据、数据是否已经接受完成、数据接收失败
2.block注重结果的传输:比如对于一个事件,只想知道成功或者失败,并不需要知道进行了多少或者额外的一些信息