本文章从五个方面介绍KVO(Key-Value-Observer)键值观察者:

(1)功能介绍

(2)使用步骤

(3)应用场景

(4)原理理解

(5)相关的面试题

一 功能介绍

  • KVO是OC语言对「观察者设计模式」的一种实现。
  • 只要是NSObject的子类的实例对象,利用KVO机制可以监听该对象的指定属性的值,当属性值发生变化的时候,监听者就能获得通知,就能作出相应的处理。
  • KVO触发机制:一个对象(观察者),监听另一个对象(被观察者)的某属性是否发生变化,若被监听的属性发生了更改,会触发观察者的一个方法(方法名是固定的,类似于代理方法)
  • 使用KVO的好处之一是,不需要给被观察的实例对象添加任何额外的代码,就能对其实施监听。
  • KVO的实现依赖于OC的运行时系统。

二 使用步骤

1、注册观察者

[<#要观察的实例对象#> addObserver:<#作为观察者的实例对象#> forKeyPath:<#要观察的实例对象的指定属性名#>
options:<#选项#> context:<#上下文,可以为KVO的回调方法传值#>];

关于options参数

typedef NS_OPTIONS(NSUInteger, NSKeyValueObservingOptions) {
//把更改之前的值提供给监听者的回调方法
NSKeyValueObservingOptionNew ,
//把更改之后的值提供给监听者的回调方法
NSKeyValueObservingOptionOld ,
//把初始化的值提供给监听者的回调方法,一旦注册立马就会调用一次。通常它会带有新值,而不会带有旧值
NSKeyValueObservingOptionInitial ,
//分两次调用监听者的回调方法。在值改变之前和值改变之后
NSKeyValueObservingOptionPrior
};

2、在回调方法中处理属性发生的变化

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change
(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context { if ([keyPath isEqualToString:@"name"]) {
id oldValue = [change objectForKey:@"old"]; id newValue = [change objectForKey:@"new"]; NSLog(@"%@~%@~%@", change, oldValue, newValue);
}
}

3、触发回调方法

使用setter方法或者KVC更改监听对象的指定属性,才会触发KVO。

4、移除观察者

注册观察者和移除观察者一定要成对出现。可以在dealloc中移除观察者,也可以在适当的时候提前手动移除观察者。

- (void)dealloc {
[self removeObserver:self forKeyPath:@"name"];
}

ps:一般使用KVO崩溃的原因:

(1)被观察的对象销毁了(比如被观察的对象被一个局部变量持有)

(2)观察者被释放掉了,但是没有移除监听(比如模态推出,push,pop等)

(3)注册的监听没有移除掉,又重新注册了一遍监听

三 应用场景

在MVC设计模式中,负责Model和View之间的同步。

比如,监听Model层,当Model层的数据发生更改时,同步View中的显示。

四 原理理解

比如我们要对Person类的实例对象person的name属性利用KVO机制实施监听属性值的变更通知。

第一步:运行时系统动态创建一个Person的子类:NSKVONotifying_Person

第二步: 将实例对象person的isa指针由原来的指向Person类,改为指向NSKVONotifying_Person类

第三步:改写NSKVONotifying_Person类中name属性的setter方法的实现:

(tips)-willChangevalueForKey:和-didChangeValueForKey:两个方法是KVO机制中向系统发送通知的实现。因此,上面提到的“触发回调方法”中,只说明了通过setter方法和KVC才能触动KVO机制,对属性直接赋值的方法是不能触发的,比如_name = @"XiaoMing";但是在了解KVO的原理之后,只要用上刚刚所知道的那两个方法,就行了。比如:

五 相关的面试题

(1)KVO与KVC的区别?

KVC是键值编码,提供了一种使用字符串直接访问和设置对象的属性的方式;

KVO是键值监听,提供了一种观察实例对象的指定属性的一种机制。

(2)KVO与Notifacation(通知)、delegate(代理)的区别?

Delegate的特点有:

1、1对1的传值

2、支持正向与反向传值(参数、返回值)

2、可以用require和optional来修饰

因此在使用delegate时,除了正常的通过参数传值,还可以灵活的运用返回值。

Notification的特点有:

1、1对多的传值

2、不关心返回值,单向的传值

3、NSNotificationCenter单例统一处理发通知

4、通过不同的唯一通知标识名NotificationName区分不同通知

5、被观察者主动发出通知

因此使用Notification一定要谨慎,由于1对多的缘故,避免滥用,不好查问题

其次就是注意要及时注销掉通知。比如:

KVO的特点有:

1、1对多

2、只能监听对象的属性变化,比较局限

3、只有通过KVC和setter方法才触发KVO

4、被观察者不用添加任何代码(比如由被观察者发出通知),观察者与被观察者完全解耦

5、注册观察者时,属性名都是通过字符串来查找,容易出错

6、KVO的要求是对象必须支持KVC机制(即必须是NSObject的子类)

7、也是属于单向传值

(3)KVO的优缺点?

优点:

1、能够提供一种简单的方法实现两个对象之间的同步,例如model和view之间的同步

2、能够对非我们创建的对象,即内部对象的状态作出响应,而且不需要改变内部对象的实现

3、能够提供观察的属性的最新值和先前值

4、使用的是keyPath来观察属性,因此也可以观察嵌套对象

5、完成了对观察对象的抽象,因为不需要额外的代码来允许观察值能够被观察

缺点:

1、我们观察的属性必须使用string来定义。因此在编译期不会出现警告以及检查

2、如果我们对属性进行了重构,那么之前KVO的代码需要重写

3、当释放观察者时需要移除观察者

4、KVO只能对属性作出反应,而不会对方法作出反应

使用KVO键值监听的更多相关文章

  1. KVO键值监听

    KVO 键值监听:当我想知道一个对象的属性是否发生改变的时候 做出响应,就需要添加监听keypath 和 key的区别keypath会自动寻找子类的属性key只会寻找当前类的属性添加键值监听[pers ...

  2. ios中键值编码kvc和键值监听kvo的特性及详解

    总结: kvc键值编码  1.就是在oc中可以对属性进行动态读写(以往都是自己赋值属性)           2. 如果方法属性的关键字和需要数据中的关键字相同的话                  ...

  3. iOS监听模式系列之键值编码KVC、键值监听KVO的简单介绍和应用

    键值编码KVC 我们知道在C#中可以通过反射读写一个对象的属性,有时候这种方式特别方便,因为你可以利用字符串的方式去动态控制一个对象.其实由于ObjC的语言特性,你根部不必进行任何操作就可以进行属性的 ...

  4. Unity3d 中键值监听方法

    unity3d的api中没有负责监听键值的方法,不过unity的input类是通过c#类获取各类监听事件,所以我们可以通过c#类监听,方法如下: void OnGUI() { Event e = Ev ...

  5. KVO-键值监听

    键值监听,就是可以监听对象某个属性值的变化: 首先,在工程中,新建一个Person的类 @interface Person : NSObject @property (nonatomic, copy) ...

  6. KVO 键值观察者

    KVO(键值观察者) //监听的创建 -(id)initChildren:(Person *)person { self = [super init]; if (self != nil) { //拥有 ...

  7. Android应用中返回键的监听及处理

    MainActivity: package com.testnbackpressed;  import android.os.Bundle;  import android.view.KeyEvent ...

  8. Android应用中Back键的监听及处理

    MainActivity如下: package cn.testnbackpressed; import android.os.Bundle; import android.view.KeyEvent; ...

  9. Key-Value Observing (键值监測)

    Key-Value Observing (键值监測) 简单介绍 KVO是一套当目标对象的属性值改变时观察者对象能够接受到通知的机制.必须先理解KVC才干更好的理解KVO,前者是后者的实现基础. 这种通 ...

随机推荐

  1. P2023 [AHOI2009]维护序列 区间加乘模板

    题意: 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式:N<=1e5(1)把数列中的一段数全部乘一个值;(2)把数列中的一段数全部加一个值;(3)询问数列中的一段数的和,由于 ...

  2. 506,display有哪些值?说明他们的作用

    block:转换成块状元素 inline:装换成行内元素 none:设置元素不可见 inline-block:想行内元素那样显示,但是其内容像块类型元素一样显示 list-item:想块类型元素一样显 ...

  3. Jmeter 测试结果分析之聚合报告简介

    聚合报告(aggregate report) 对于每个请求,它统计响应信息并提供请求数,平均值,最大,最小值,错误率,大约吞吐量(以请求数/秒为单位)和以kb/秒为单位的吞吐量. 吞吐量是以取样目标点 ...

  4. find 报错 find: paths must precede expression:

    编写shell脚本,报错,如下面 [root@localhost backup]#find ./ -name mysqldump* -mtime +3 -delete [root@localhost ...

  5. C 语言实例 - 约瑟夫生者死者小游戏

    30 个人在一条船上,超载,需要 15 人下船. 于是人们排成一队,排队的位置即为他们的编号. 报数,从 1 开始,数到 9 的人下船. 如此循环,直到船上仅剩 15 人为止,问都有哪些编号的人下船了 ...

  6. jmeter实现对Oracle数据库的操作

    实现目的 有时候,根据业务需要,可能需要直接对数据库进行性能测试,此时可利用jmeter对Oracle.MySQL等数据库进行相关测试. 脚本实现 添加JDBC Connection Configur ...

  7. Linux挂载(mount,umount及开机自动挂载

    挂载概念简述: 根文件系统之外的其他文件要想能够被访问,都必须通过“关联”至根文件系统上的某个目录来实现,此关联操作即为“挂载”,此目录即为“挂载点”,解除此关联关系的过程称之为“卸载” 1.挂载:根 ...

  8. keil(MDK)错误记录

    1.a parameter list without types is only allowed in a function definition(没有类型的参数列表只允许在函数定义中使用) 2.Er ...

  9. LeetCode 编辑距离(DP)

    题目 给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 . 你可以对一个单词进行如下三种操作: 插入一个字符 删除一个字符 替换一个字符 思路 定 ...

  10. jdk 9 10 11 12 13 新特性

    jdk 9 新特性 1.集合加强 jdk9 为所有集合(List/Set/Map)都增加了 of 和 copyOf 方法,用来创建不可变集合,即一旦创建就无法再执行添加.删除.替换.排序等操作,否则将 ...