kvo实现原理_KVO实现原理

有关KVO (Key-Value Observing)大家一定不会觉得陌生,常常被用来监听某个对象属性值的改变。那么有关底层实现原理是需要来探讨的,今天就来说说KVO的基本使用以及实现原理。

什么是KVO

KVO (Key-Value Observing) 是 Objective-C 对观察者模式(Observer Pattern)的实现。当被观察者对象的某个被观察属性发生变化时,观察者对象会获得通知。

苹果官方文档中对KVO的定义是

Automatic key-value observing is implemented using a technique called isa-swizzling. The isa pointer, as the name suggests, points to the object's class which maintains a dispatch table. This dispatch table essentially contains pointers to the methods the class implements, among other data. When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class. As a result the value of the isa pointer does not necessarily reflect the actual class of the instance. You should never rely on the isa pointer to determine class membership. Instead, you should use the class method to determine the class of an object instance.

从中可以看到并不想我们想象的那么简单,KVO的实现中使用了黑魔法 isa-swizzling,后面将描述其实现过程。

下面先来看KVO的基本使用。

KVO的基本使用

以下使用官方文档中的Example为例(官方文档)。

创建两个类,Person类和Account类。假使一个Person对象拥有一个Account对象,代表一个人在银行的储蓄账号。这样,当银行的收益和利率变化时这个人必须时刻注意到。在Account类中添加两个公共属性,如图所示:

942f8065dfb44d01e7520e548ee1719c.png

既然Account类的属性是公共的,Person对象可以通过轮询查找来获取Account属性值的变化,但显然这样效率低下。

1、为Person对象添加监听对象,调用方法:addObserver:forKeyPath:options:context:。

2、在Person类中实现observeValueForKeyPath:ofObject:change:context:方法。这样,当Account属性值发生变化时就会调用此方法,将其值的变化通知过来。

110e0abf661b3a69a4ca8ae9b795e8d5.png

3、最后,当不再希望收到通知时一定要在Person类销毁时注销通知,调用removeObserver:forKeyPath:方法。

d28b267d5f276721a36f79f8a92e3224.png

实现原理

KVO是基于Runtime实现的,其实现过程 ChenYilong (微博@iOS程序犭袁)在下面这张图中画的很明白。

687474703a2f2f6936322e74696e797069632e636f6d2f7379353775722e6a7067

当观察一个对象的时候,运行期系统会动态创建一个新的类。

这个类继承自该对象的原本的类,并重写了被观察属性的 setter 方法。重写的 setter 方法会负责在调用原 setter 方法之前和之后(被观察属性发生改变之前 willChangeValueForKey:方法会被调,被观察的属性发生改变之后didChangeValueForKey:方法则会被调用),通知所有观察对象:值的更改。

最后通过 isa 混写(isa-swizzling) 把这个对象的 isa 指针 ( isa 指针告诉 Runtime 系统这个对象的类是什么 ) 指向这个新创建的子类,对象就神奇的变成了新创建的子类的实例。

感谢 ChenYilong 在《《招聘一个靠谱的 iOS》—参考答案(下)》中的精彩答案,节省了我很多时间去研究KVO的实现细节。

手写KVO

这里推荐Glow 技术团队博客上的一篇文章《如何自己动手实现 KVO》,文章里关于KVO实现细节是我在网上看到最全的,而且附带源码。感兴趣的同学可以去看看。这里就不浪费空间贴大量代码了。

KVO的不足

KVO一度被认为是非常不好的API,比如其 以字符串作为关键字、remove observer不当会导致crash,《Key-Value Observing Done Right》、《KVO Considered Harmful》以及Mattt Thompson在《Key-Value Observing》中都强调了KVO的不足之处,有兴趣可以去看下。

参考文章

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值