KVC是KVO的技术基础,他们都是利用了OC的动态性。
概念
KVC
NSKeyValueCoding
A mechanism by which you can access the properties of an object indirectly by name or key.
译:它是一种可以通过字符串的名字(key)来访问类属性的机制。而不是通过调用Setter、Getter方法访问。
KVO
全称是Key-value observing,翻译成键值观察。提供了一种当其它对象属性被修改的时候能通知当前对象的机制
常用方法
KVC
所有的方法都在Foundation库的NSKeyValueCoding.h
中
///为对象的属性赋值
-(void)setValue:(nullable id)value forKey:(NSString *)key;
// 根据key取值
- (id)valueForKey:(NSString *)key;
// 为对象的属性赋值(包含了setValue:forKey:的功能,并且还可以对对象内的类的属性进行赋值)
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
// 根据keyPath取值
- (nullable id)valueForKeyPath:(NSString *)keyPath;
// 对模型一次性赋值,前提是必须声明好所有对应的属性(key)
- (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues;
KVO
所有的方法都在Foundation库的NSKeyValueObserving.h
中
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
应用
CoreData
修改系统控件的内部属性(Runtime+KVC)
其他
KVO与Notification(通知)的区别?
notification 比 KVO 多了发送通知的一步。
两者都是一对多,但是对象之间直接的交互,notification 明显得多,需要notificationCenter 来做为中间交互。而 KVO 如我们介绍的,设置观察者->处理属性变化,至于中间通知这一环,则隐秘多了,只留一句“交由系统通知”,具体的可参照以上实现过程的剖析。
notification 的优点是监听不局限于属性的变化,还可以对多种多样的状态变化进行监听,监听范围广,例如键盘、前后台等系统通知的使用也更显灵活方便。
实现原理
KVC
当某个类的对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的 setter 方法。
派生类在被重写的 setter 方法实现真正的通知机制,就如前面手动实现键值观察那样。这么做是基于设置属性会调用 setter 方法,而通过重写就获得了 KVO 需要的通知机制。当然前提是要通过遵循 KVO 的属性设置方式来变更属性值,如果仅是直接修改属性对应的成员变量,是无法实现 KVO 的。
同时派生类还重写了 class 方法以“欺骗”外部调用者它就是起初的那个类。然后系统将这个对象的 isa 指针指向这个新诞生的派生类,因此这个对象就成为该派生类的对象了,因而在该对象上对 setter 的调用就会调用重写的 setter,从而激活键值通知机制。此外,派生类还重写了 dealloc 方法来释放资源。
KVO
当某个类的对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的 setter 方法。
派生类在被重写的 setter 方法实现真正的通知机制,就如前面手动实现键值观察那样。这么做是基于设置属性会调用 setter 方法,而通过重写就获得了 KVO 需要的通知机制。当然前提是要通过遵循 KVO 的属性设置方式来变更属性值,如果仅是直接修改属性对应的成员变量,是无法实现 KVO 的。
同时派生类还重写了 class 方法以“欺骗”外部调用者它就是起初的那个类。然后系统将这个对象的 isa 指针指向这个新诞生的派生类,因此这个对象就成为该派生类的对象了,因而在该对象上对 setter 的调用就会调用重写的 setter,从而激活键值通知机制。此外,派生类还重写了 dealloc 方法来释放资源。