返回

从 KVO 原理到源码,一文讲透彻!

IOS

作为一名从业 10 年的 iOS 开发者,我对 KVO(Key-Value Observing,键值观察)有着深厚的感情。从最初对它的懵懂无知,到后来逐渐掌握它的原理和用法,再到如今将其作为开发利器,一路走来,感慨万千。

一、KVO 的原理

KVO 是 Objective-C 中实现观察者模式的一种机制,它允许对象监视其他对象的属性变化,并在属性发生变化时收到通知。这种机制在开发中非常有用,比如:

  • 当某个模型对象的属性发生变化时,通知视图控制器进行界面更新。
  • 当某个服务对象的属性发生变化时,通知其他服务对象进行数据同步。

KVO 的实现原理是通过运行时动态生成一个子类,该子类继承自被观察对象,并在子类中重写被观察属性的 getter 和 setter 方法。当被观察属性发生变化时,重写的 getter 和 setter 方法就会被调用,从而触发通知。

二、KVO 的使用

在使用 KVO 时,我们需要首先将观察者对象添加到被观察对象的观察者列表中。可以使用以下方法来添加观察者:

- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
  • observer:观察者对象。
  • keyPath:被观察的属性路径。
  • options:观察选项。
  • context:上下文信息。

当被观察属性发生变化时,观察者对象就会收到通知。可以使用以下方法来处理通知:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context;
  • keyPath:被观察的属性路径。
  • object:被观察对象。
  • change:属性变化信息。
  • context:上下文信息。

三、KVO 的源码分析

KVO 的源码实现非常复杂,涉及到运行时、消息转发等多个知识点。在这里,我们只简单分析一下 KVO 的核心实现原理。

KVO 的核心实现原理是通过运行时动态生成一个子类,该子类继承自被观察对象,并在子类中重写被观察属性的 getter 和 setter 方法。当被观察属性发生变化时,重写的 getter 和 setter 方法就会被调用,从而触发通知。

运行时动态生成子类的过程如下:

  1. 获取被观察对象的类对象。
  2. 使用运行时创建一个新的类对象,该类对象继承自被观察对象的类对象。
  3. 在新的类对象中重写被观察属性的 getter 和 setter 方法。
  4. 将新的类对象与被观察对象关联起来。

重写被观察属性的 getter 和 setter 方法的过程如下:

  1. 获取被观察属性的类型。
  2. 根据被观察属性的类型生成 getter 和 setter 方法的实现代码。
  3. 将 getter 和 setter 方法的实现代码添加到新的类对象中。

四、KVO 的应用场景

KVO 在开发中有很多应用场景,比如:

  • 当某个模型对象的属性发生变化时,通知视图控制器进行界面更新。
  • 当某个服务对象的属性发生变化时,通知其他服务对象进行数据同步。
  • 当某个对象的属性发生变化时,记录属性变化的历史记录。
  • 当某个对象的属性发生变化时,触发某个事件。

五、KVO 的优缺点

KVO 的优点:

  • 使用简单,只需要添加和移除观察者即可。
  • 观察者和被观察对象之间解耦,观察者无需了解被观察对象的内部实现。
  • 支持多级观察,可以观察嵌套对象的属性变化。

KVO 的缺点:

  • 性能开销大,特别是对频繁变化的属性。
  • 可能会导致循环引用,如果观察者和被观察对象相互持有引用,可能会导致内存泄漏。
  • 不支持 KVC(Key-Value Coding,键值编码)。

六、总结

KVO 是 Objective-C 中实现观察者模式的一种机制,它允许对象监视其他对象的属性变化,并在属性发生变化时收到通知。KVO 的使用非常简单,只需要添加和移除观察者即可。KVO 的原理是通过运行时动态生成一个子类,该子类继承自被观察对象,并在子类中重写被观察属性的 getter 和 setter 方法。当被观察属性发生变化时,重写的 getter 和 setter 方法就会被调用,从而触发通知。KVO 的应用场景非常广泛,比如:当某个模型对象的属性发生变化时,通知视图控制器进行界面更新;当某个服务对象的属性发生变化时,通知其他服务对象进行数据同步。KVO 的优点是使用简单,观察者和被观察对象之间解耦,支持多级观察。KVO 的缺点是性能开销大,可能会导致循环引用,不支持 KVC。