Delegate
优点:强制实现一些方法,不实现时编译器会报错、返回处理多种情况的结果、方法名比较明了.因为 delegate 协议可以定义任何的方法,我们可以照着自己的需求来传递消息
缺点:代码量比较大,用完之后需要将delegate对象置为nil
NSNotification
优点:不需要关心业务间逻辑,发送、传值、监听.1对多、 要在代码中的两个不相关的模块中传递消息时,通知机制是非常好的工具。
缺点:编译时不会检查监听的通知名是否正确、调试时难追踪没有逻辑可言、只传值不关心处理结果、通知可以被用来在不同的相隔很远的模块之间传递消息。这就意味着这种消息传递是单向的,我们不能回复一个通知。
KVO
优点:我们没有必要发送通知就能监听值得改变,苹果已经帮我们做好了这些事情.、通过keyPath观察属性的变化,甚至是嵌套对象的属性,实时处理一些情况的变化.
缺点:监听的属性名不会在编译的时候做检查
比如一个人需要关心他银行卡金额的变化,personObject注册一个监听 addObserver:forKeyPath:options:context:
observeValueForKeyPath:ofObject:change:context:
Block
block首地址是*isa的结构体指针,也可以认为是对象(id)
创建block实际上就是在方法中声明一个struct,编译器根据block捕获的变量生成具体的结构体定义.捕获的变量会赋值到结构体的成员上,初始化完成捕获的变量不可修改
第一次创建后存在栈上、myBlock->impl.isa =&__NSConcreteStackBlock
执行block时,就是调用单独的C函数,并把struct的指针传过去.
函数返回时,Block的内存也会清除,如果结束仍需要保留这个block,必须用Block_copy()方法把它拷贝到堆上_NSConcreteMallocBlock,将Class改一下,捕获的对象发送retain,增加block的引用计数
block的isa指向block的class,block_copy()和block_release()一一匹配,否则会出现内存泄漏
__block类型的变量:Block能访问并且能修改外部的局部变量,原本是int的值就变成了一个struct,这个struct的首地址同样为isa相当于一个对象,被Block共享,不受栈生命周期的限制.
block对变量的捕获规则:
静态储存区变量:全局变量、static修饰变量可以修改
block接受的参数,和别的函数一样,可以修改
栈变量(被捕获到上下文的变量)、const,不可修改当block被copy后,block会对 id类型的变量产生强引用。每次执行block时,捕获到的变量都是最初的值。
__block引用,可以修改。如果时id类型则不会被block retain,必须手动处理其内存管理。
如果该类型是C类型变量,block被copy到heap后,该值也会被挪动到heap
循环引用:
self对block引用,block捕捉到self时
XYZBlockKeeper*__weakweakSelf=self; self.block=^{ [weakSelf doSomething];//捕获到的是弱引用 }
如果捕获到的是当前对象的成员变量对象,同样也会造成对self的引用
id tmpIvar=_ivar;//临时变量,避免了self引用 self.block=^{ [tmpIvar msg]; }