iOS之KVC、KVO、Delegate、NSNotification区别


总结:

1、KVC方式可以更便捷的设置获取对象的值(批处理,键路径、修改类的私有变量,修改IOS隐藏属性);KVO可以对对象进行监听属性的变化。

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的底层实现?

赋值:当执行[myObject valueForKey:@”name”]
假设没有定义属性name,系统就会根据key来进行一个搜索,那么KVC执行规则是:依次搜索
- (NSString*) getName方法,
- (NSString*) name方法,
- (NSString*) isName方法,这三个方法的先后顺序来查找,如果有,则执行相应的方法,(这是按NSString类型的查找规则)。

如果没有则继续找,因为key:@”name”,系统也不知道查找的name是什么类型的,那么系统会 按照其他数据类型的方式继续找,如数组NSArray查找方式是会找这两个方法

- (NSUInteger) countOfName
- (id) objectInNameAtIndex:(NSUInteger)index

如果找到了就执行。 
依此类推还有其他数据类型的查找方式,不一一例举出来了,重点是了解有这么一个过程,KVC原理。

取值:当执行setValue:forkey:
假设没有自定属性name,那么底层会怎么做呢, 系统执行的操作: 
1、系统会去找setName:属性值方法,如果有找到setName:方法,就直接赋值;没有继续后面流程
2、系统检查(BOOL)accessInstanceVariablesDirectly方法返回值(系统默认YES)
3、如果返回NO,执行setValue:ForUndefineKey:方法,如果当前类没有重写该方法,系统抛出异常,程序Crash;如果重写了,执行该方法并结束流程。
4、如果返回YES,继续搜索类成员变量赋值如果找了相应变量,就停止寻找。搜索顺序依次是_name、_isName、name、isName

注意 :当对NSDictionary对象使用KVC时,valueForKey:和objectForKey:效果一样。
可以看出利用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。不建议过分的使用通知中心,会让人很难理解应用的流程。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值