iOS中的KVO机制剖析

Posted by GeorgeWang on December 22, 2015

KVO即 key value observing键值对观察,是objc中的一种机制。 KVO以KVC(key value coding)为基础,通过向对象的某个键值添加观察者,当对象键所对应的值发生变化时,通知观察者,执行相关的回调方法。

以下描述分为KVO的使用,OBJC实现KVO机制的剖析,KVO的DIY,fb的KVO开源库介绍,四部分。

Tips:

	KVO的操作回调是在同一个线程中进行的,和NOTIFICATION一样

1. KVO的使用

objc中给对象键值添加观察者,通过:

[obj addObserver:forKeyPath:option:context:]

回调函数:


observeValueForKeyPath:ofObject:change:context:

移除通知:(这是一定要的,不然会导致crash)

removeObserver:forKeyPath:

2. OBJC实现KVO机制的剖析

先贴上几个解析来源:

1.《招聘一个靠谱的iOS》面试题

2.https://www.mikeash.com/pyblog/friday-qa-2009-01-23.html

objc通过什么来实现对键值添加观察者并发送通知呢?

objc基于runtime,以setter方法为入口,实现这一机制。 首先需要知道的是,objc的对象实例isa指针,内存布局,Class结构体表示类。

当向对象添加键值观察者时,objc通过runtime动态生成对象所属的类的子类,重写setter,并将对象的isa指针指向新类,在此过程中还重写了子类的class方法,向开发者隐藏新建子类 (也就是所谓的isa混写(isa-swizzling))。

在新的类的setter中,执行:

[super setObject:]

并在前后执行:

[self willChangeValueForKey:]与[self didChangeValueForKey:]

并在后者执行时调用观察者的回调函数,所以在观察者dealloc时必须注销所设置的观察,否则会发送消息给dealloc对象,造成crash。

##3. KVO的DIY 照例贴上手动实现KVO的方法链接:http://tech.glowing.com/cn/implement-kvo/

通过上面的剖析,我们知道了KVO的实现原理

如果要手动实现,那有两个过程必须实现

1.添加观察者接口及过程
2.键值改变时的通知过程实现

1.添加观察者接口及过程

1.1 检查对象的类有没有相应setter方法,如果没有抛出异常;
	检查对象 isa 指向的类是不是一个有kPGKVOClassPrefix前缀的KVO类,如果不是需要创建新子类,并把isa指针指向新类,实现class方法

1.2 检查有没有KVO的setter方法,没有的话构建新类的setter方法

1.3 把观察者添加到观察者列表,使用***关联对象(objc_setAssociationObj)*** 绑定列表

2.键值改变时的通知过程实现

2.1 通过runtime动态执行父类也就是原来的类的setter方法

2.2 取出有关keyPath的观察者,并逐一调用回调函数block


##4.KVOController

👉 FaceBook的KVOController链接

KVOController是Facebook开源的一个KVO库,其可以聚合KVO操作,使用block执行观察操作,好处是可以不用自己去remove观察者,防止因为忘记remove造成crash,以下是其用法:


// create KVO controller with observer
FBKVOController *KVOController = [FBKVOController controllerWithObserver:self];
self.KVOController = KVOController;

// observe clock date property
[self.KVOController observe:clock keyPath:@"date" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew block:^(ClockView *clockView, Clock *clock, NSDictionary *change) {

  // update clock view with new value
  clockView.date = change[NSKeyValueChangeNewKey];
}];

总结

KVO 是objc一项重要的特性和设计模式,也是GOF观察者模式的实现。开发中经常用于观察数据层(data)变化而对视图层(view)作出相应的改变,也是一种响应方式。由于其需要手动移动观察,否则会导致crash,所以使用时需要小心。Facebook的KVOController对objc的KVO进行封装,使用block模式,让开发者更省心。KVO在objc的底层实现是isa混编,生成子类并重写setter,然后通知观察中。手动实现KVO需要对类做是否KVO子类的判断,从而决定是否生成子类。总而言之,KVO是objc中一个比较重要的语言特性,使用好它,能为你带来不小的好处。


分享到: