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 *)keyPathofObject:(nullable id)objectchange:(nullable NSDictionary *)changecontext:(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 。若直接访问属性对象则没有效果。


【KVC和KVO】具体demo:KVC-KVO-Demo

    推荐阅读