KVC和KVO

本篇主要是介绍KVC和KVO的使用方法和实现原理

基本概念:

1-1. KVC基本概念:

KVC 即 Key-Value Coding,翻译成键值编码。它是一种不通过存取方法,而通过属性名称字符串间接访问属性的机制。

  1-2. KVC的基本用法:

  KVC 常用到的方法有下面几个:

  - (id)valueForKey:(NSString *)key;

  - (void)setValue:(nullable id)value forKey:(NSString *)key;

 - (nullable id)valueForKeyPath:(NSString *)keyPath;

  - (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;

1-3. KVC的基本原理

KVC的原理 为了设置或者获取对象属性,KVC按顺序使用如下技术: 获取对象属性时,检查是否存在 - ,  -is(只针对布尔值有效)或者 -get的访问器方法,如果找到,就用这些方法来返回属性值;设置对象属性时,检查是否存在名为 -set: 的方法,并使用它来设置属性值。对于 -get和 -set: 方法,将大写Key字符串的第一个字母,并与Cocoa的方法命名保持一致。 如果上述方法找不到,则检查名为 -_、 -_is(只针对布尔值有效)、 -_get和 -_set: 方法。 如果没有找到访问器方法,则尝试直接访问实例变量。实例变量可以是名为:或 _

    如果仍未找到,则调用 valueForUndefinedKey: 和 setValue:forUndefinedKey: 方法。这些方法的默认实现都是抛出异常,可以根据需要重写它们。

    可以看到,KVC会优先使用访问器方法来访问对象属性。

2-1. KVO的基本概念:

 KVO 即 Key-Value Observing,翻译成键值观察。它是一种观察者模式的衍生。其基本思想是,对目标对象的某属性添加观察,当该属性发生变化时,通过触发观察者对象实现的KVO接口方法,来自动的通知观察者。

   KVO可以在MVC模式中得到很好的应用。因为当Model发生变化时,通过KVO可以很方便地通知到Controller,从而通过Controller来改变View的展示。所以说KVO是解决Model和View同步的好办法。

2-2. KVO的基本用法  (最好配合单例使用) :

 KVO的使用主要分为三步:

 第一步,将目标对象添加为观察者。(注意这里用到了KVC,即通过字符串的方式去访问属性值。但是,也可以不用,直接更改其属性) 

 - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context; 

 第二步,实现接收通知的接口方法。

 - (void)observeValueForKeyPath:(nullable NSString *)keyPath  ofObject:(nullable id)object      change:(nullable NSDictionary *)change      context:(nullable void *)context;

    第三步,移除观察者。

    - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;

2-3. KVO的原理

KVO的实现依赖于Runtime的强大动态能力。

当某个类的对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写这个类中任何被观察属性的 setter 方法。

即当一个类型为 ObjectA 的对象,被添加了观察后,系统会生成一个 NSKVONotifying_ObjectA 类,并将对象的isa指针指向新的类,也就是说这个对象的类型发生了变化。这个类相比较于ObjectA,会重写以下几个方法。

1. 重写setter

在 setter 中,会添加以下两个方法的调用。

- (void)willChangeValueForKey:(NSString*)key;

- (void)didChangeValueForKey:(NSString*)key;

然后在 didChangeValueForKey: 中,去调用:

- (void)observeValueForKeyPath:(nullableNSString*)keyPath ofObject:(nullableid)object change:(nullableNSDictionary *)change context:(nullablevoid*)context;

于是实现了属性值修改的通知。因为 KVO 的原理是修改 setter 方法,因此使用 KVO 必须调用 setter 。若直接访问属性对象则没有效果。


具体demo:KVC-KVO-Demo

你可能感兴趣的:(KVC和KVO)