作为非常常见,且无处不在的block和delegate,理解它们,是我们掌握iOS开发必备知识点。
1.从源头上理解和区别block和delegate
delegate运行成本低,block的运行成本高。
block出栈需要将使用的数据从栈内存拷贝到堆内存,当然对象的话就是加计数,使用完或者block置nil后才消除。delegate只是保存了一个对象指针,直接回调,没有额外消耗。就像C的函数指针,只多做了一个查表动作。
2.从使用场景区别block和delegate
有多个相关方法。假如每个方法都设置一个 block, 这样会更麻烦。而 delegate 让多个方法分成一组,只需要设置一次,就可以多次回调。当多于 3 个方法时就应该优先采用 delegate。当1,2个回调时,则使用block。
delegate更安全些,比如: 避免循环引用。使用 block 时稍微不注意就形成循环引用,导致对象释放不了。这种循环引用,一旦出现就比较难检查出来。而 delegate 的方法是分离开的,并不会引用上下文,因此会更安全些。
delegate回调返回的参数被限制在了 NS 类的范围内,数量也很有限(当然可以用直接调用方法的形式在绕过,并不推荐;也可以用 Array 套着传, 不过这样需要有文档支持,不然不够清晰,回调方法也需要独立的验证,故也不推荐)。
那如何使用?
如果你从其他语言转到 Objective-C 或者 Swift ,相信 Delegation 肯定让你觉得更加亲切,那么在初级阶段请使用好这个语法糖,多用,多去理解;如果你用着 AFNetworking 看着其他老前辈的说法用 Block 觉得效率很高很开心,那就开心的用,直到你被循环引用烦到了为止;然后,在你代码写多了之后,你可以开始尝试接触其他回调方式,去感受这些回调方式的不同。关键在于对于回调流程的理解。你要知道你的回调是一个什么性质的回调,如果这个回调是一个不定期触发,或者会多次触发的,那么 Delegation 应该更适合;如果这个回调是一个一次性的,并且和调用方法是单线性关系的,那么 Block 应该更适合。在不同的执行线(不是线程),不同的执行次数、执行数量上的区别,是鉴别使用哪一种回调的最好判断方法。
对于 Block 来说,他的执行线应该是和调用方法、回调方法连续在一起的;对于 Delegation 和 他的执行线可以是连续的,也可以是调用方法和回调方法之间有很长的间隔,或者说回调方法在执行线上会多次出现。
(1)delegate
解决对象对象间通信问题的关键:判断谁是代理对象,谁是被代理对象。
谁产生事件,就是被代理对象。被代理对象有一个delegate属性,并且在这个类里面定义一个protocol及其方法并且调用`,注意只是定义和调用,具体实现在下面的类里面。 定义的时候要注意用assign,如果用strong会出现内存泄漏:VC—>view—>tableView—>delegate(self即VC)
谁响应事件,就是代理对象。代理对象需要遵守协议,并且实现协议里面规定的方法
(2)block
解决对象对象间通信问题的关键:判断谁回调block,谁传递block (类似于delegate)
谁产生事件,谁就回调block。这个需要回调block的类需要定义block并且有一个block属性(定义block属性时需要用copy)。
谁响应事件,谁就传递block。接受到事件传递block时,block里面的具体操作在这里定义,但在传递时不会执行,执行是在上面回调block时block执行
(3)定义block属性需要用copy的原因
Block存储在栈区,栈区的特性是当一个方法运行完成之后里面的内存就会释放掉,如果block被释放,那么后面回调就会遇到问题,所以要把block复制到堆区来存储。所以用copy把整个block内容拷贝过来并且在堆区新建一块空间来存储block
(4)__block关键字的使用
首先,如果要在block内部修改局部变量,需要用__block修饰。当然被此关键字修饰的指针仍然是强指针,为了避免循环引用,修改前需要用__weak重新定义一个弱指针。例如
__weak typeof(self) weakSelf = self;
[yourBlock:^(NSArray *repeatedArray, NSArray *incompleteArray) {
[weakSelf doSomething];
}];
(5)几种通信方式的对比
delegate:
1.“一对一”,对同一个协议,一个对象只能设置一个代理delegate,所以单例对象就不能用代理;
2.代理更注重过程信息的传输:比如发起一个网络请求,可能想要知道此时请求是否已经开始、是否收到了数据、数据是否已经接受完成、数据接收失败
block:
1.写法更简练,不需要写protocol、函数等等
2.block注重结果的传输:比如对于一个事件,只想知道成功或者失败,并不需要知道进行了多少或者额外的一些信息
3.block需要注意防止循环引用:
http://www.cocoachina.com/cms/wap.php?action=article&id=23147
网友评论