总结:
2、NSNotification、KVC、KVO都是运用了设计模式中的观察者模式(监听模式), delegate是设计模式中的委托模式。
3、使用任何一种模式都没有对和错,只有更适合或者不适合。根据经验,使用优先级:KVO > Delegate > NSNotification
NSNotification
消息中心实质是设计模式中的观察者模式,是一种一对多的关系,消息发送者只负责发送消息,不能接收消息。NSNotificationCenter提供了一种更加解耦的方式。最典型的应用就是任何对象对可以发送通知到中心,同时任何对象可以监听中心的通知。
发送通知的代码如下:
[[NSNotificationCenter defaultCenter] postNotificationName:@”myNotificationName” object:broadcasterObject];
接收通知的代码如下:
[[NSNotificationCenter defaultCenter] addObserver:listenerObject selector:@selector(receivingMethodOnListener:) name:@”myNotificationName” object:nil];
注册通知的时候可以指定一个具体的广播者对象,但这不是必须的。你可能注意到了defaultCenter。实际上这是你在应用中会使用到的唯一的中心。通知会向整个应用开放,因此只有一个中心。同时还有一个NSDistributedNotificationCenter。这是用来应用间通信的。在整个计算机上只有一个该类型的中心。
优点: 通知的发送者和接受者都不需要知道对方。可以指定接收通知的具体方法。通知名可以是任何字符串。
Delegate
代理或者委托实质上是一种设计模式中的代理模式,是对象之间传递信息的一种方式,这种模式用于一个对象“代表”另外一个对象和程序中其他的对象进行交互。这是一种一对一的关系,delegate的接收者可以向这个对象返回消息。简单的说,把一个类自己需要做的一部分事情,让另一个类(也可以就是自己本身)来完成。KVC (key value coding)
KVC:他是一种简介的更改对象的状态的方式,其实现方法是使用字符串来描述对象需要更改的属性。KVC中使用:valueForKey:和setValue:ForKey:以字符串的形式想对象发送消息。
通常我们使用点语法和set方式开更改对象的状态,即为对象赋值。如:[stu setAge:10];
使用valueforKey:获取Student对象的name,如:NSString *name = [Student valueForKey :@"name"];
使用setValue:ForKey:设置student对象的name,如[Student setVlue:@"zhangjl" forKey:@"name"];
除了通过键来访问,kvc还支持通过键路径进行访问和赋值。
比如:利用键路径对Student对象的Card对象的no属性进行访问和赋值
[Student setValue:@"1234" forKeyPath: @"card.no"];
[Student valueForKeyPath:@"card.no"]
KVC的底层实现?
如果没有则继续找,因为key:@”name”,系统也不知道查找的name是什么类型的,那么系统会 按照其他数据类型的方式继续找,如数组NSArray查找方式是会找这两个方法
- (NSUInteger) countOfName
- (id) objectInNameAtIndex:(NSUInteger)index
依此类推还有其他数据类型的查找方式,不一一例举出来了,重点是了解有这么一个过程,KVC原理。
取值:当执行setValue:forkey:
1、系统会去找setName:属性值方法,如果有找到setName:方法,就直接赋值;没有继续后面流程
2、系统检查(BOOL)accessInstanceVariablesDirectly方法返回值(系统默认YES)
3、如果返回NO,执行setValue:ForUndefineKey:方法,如果当前类没有重写该方法,系统抛出异常,程序Crash;如果重写了,执行该方法并结束流程。
4、如果返回YES,继续搜索类成员变量赋值,如果找了相应变量,就停止寻找。搜索顺序依次是_name、_isName、name、isName
可以看出利用KVC可以修改类的私有变量,可以修改IOS隐藏一些属性,如UITextField的placeHolderText默认style在需求中达不到要求,我们可以直接通过KVC快速定义自己的style,代码如下:
[textField setValue:[UIColor redColor] forKeyPath:@"placeholderLabel.textColor"];
如果你了解一个UI的内部结构,你可以通过KVC可以改变系统默认的任何效果,KVC是不是很强大。
KVO使用请看这里
KVO的底层实现?
1)KVO是基于runtime机制实现的
2)当某个类的属性对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter方法。派生类在被重写的setter方法内实现真正的通知机制
3)如果原类为Person,那么生成的派生类名为NSKVONotifying_Person
4)每个类对象中都有一个isa指针指向当前类,当一个类对象的第一次被观察,那么系统会偷偷将isa指针指向动态生成的派生类,从而在给被监控属性赋值时执行的是派生类的setter方法
5)键值观察通知依赖于NSObject的两个方法: willChangeValueForKey: 和 didChangevlueForKey:;
在一个被观察属性发生改变之前, willChangeValueForKey:一定会被调用,这就会记录旧的值。
而当改变发生后,didChangeValueForKey:会被调用,继而 observeValueForKey:ofObject:change:context: 也会被调用。
6)KVO的这套实现机制中,苹果还偷偷重写了class方法,让我们误认为还是使用的当前类,从而达到隐藏生成的派生类
区别:
delegate 的 优势 :
1.非常严格的语法。所有将听到的事件必须是在delegate协议中有清晰的定义。2.如果delegate中的一个方法没有实现那么就会出现编译警告/错误
3.协议必须在controller的作用域范围内定义
4.在一个应用中的控制流程是可跟踪的并且是可识别的;
5.在一个控制器中可以定义定义多个不同的协议,每个协议有不同的delegates
6.没有第三方对象要求保持/监视通信过程。
7.能够接收调用的协议方法的返回值。这意味着delegate能够提供反馈信息给controller
缺点 :
1.需要定义很多代码:1.协议定义;2.controller的delegate属性;3.在delegate本身中实现delegate方法定义2.在释放代理对象时,需要小心的将delegate改为nil。一旦设定失败,那么调用释放对象的方法将会出现内存crash
3.在一个controller中有多个delegate对象,并且delegate是遵守同一个协议,但还是很难告诉多个对象同一个事件,不过有可能。
notification的 优势 :
1.不需要编写多少代码,实现比较简单;2.对于一个发出的通知,多个对象能够做出反应,即1对多的方式实现简单
3.controller能够传递context对象(dictionary),context对象携带了关于发送通知的自定义的信息
缺点 :
1.在编译期不会检查通知是否能够被观察者正确的处理;2.在释放注册的对象时,需要在通知中心取消注册;
3.在调试的时候应用的工作以及控制过程难跟踪;
4.需要第三方对喜爱那个来管理controller与观察者对象之间的联系;
5.controller和观察者需要提前知道通知名称、UserInfodictionary keys。如果这些没有在工作区间定义,那么会出现不同步的情况;
6.通知发出后,controller不能从观察者获得任何的反馈信息。
KVO的 优势 :
1.能够提供一种简单的方法实现两个对象间的同步。例如:model和view之间同步;2.能够对非我们创建的对象,即内部对象的状态改变作出响应,而且不需要改变内部对象(SKD对象)的实现;
3.能够提供观察的属性的最新值以及先前值;
4.用key paths来观察属性,因此也可以观察嵌套对象;
5.完成了对观察对象的抽象,因为不需要额外的代码来允许观察值能够被观察
缺点 :
1.我们观察的属性必须使用strings来定义。因此在编译器不会出现警告以及检查;2.对属性重构将导致我们的观察代码不再可用;
3.复杂的“IF”语句要求对象正在观察多个值。这是因为所有的观察代码通过一个方法来指向;
4.当释放观察者时不需要移除观察者。
1. 效率肯定是delegate比NSNotification高。
delegate方法比notification更加直接,最典型的特征是,delegate方法往往需要关注返回值,也就是delegate方法的结果。比如-windowShouldClose:,需要关心返回的是yes还是no。所以delegate方法往往包含 should这个很传神的词。也就是好比你做我的delegate,我会问你我想关闭窗口你愿意吗?你需要给我一个答案,我根据你的答案来决定如何做下一步。相反的,notification最大的特色就是不关心接受者的态度,我只管把通告放出来,你接受不接受就是你的事情,同时我也不关心结果。所以notification往往用did这个词汇,比如NSWindowDidResizeNotification,那么NSWindow对象放出这个notification后就什么都不管了也不会等待接 受者的反应。2、KVO和NSNotification的区别:
和delegate一样,KVO和NSNotification的作用也是类与类之间的通信,与delegate不同的是1)这两个都是负责发出通知,剩下的事情就不管了,所以没有返回值;
2)delegate只是一对一,而这两个可以一对多。这两者也有各自的特点。
3、根据经验,使用原则:KVO > Delegate > NSNotification
1)如果是属性层的事件,不管是在不需要编程的对象还是在紧紧绑定一个view对象的model对象,建议优先使用KVO;2)对于其他的事件,我都会使用delegate模式。
3)如果因为某种原因不能使用delegate,才使用notification。不建议过分的使用通知中心,会让人很难理解应用的流程。