KVO
KVO的本质是什么?
KVO的全称是Key-Value Observing,可以用于监听某个对象属性值的改变。
主要使用下面几个方法:
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context;
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
我们自定义一个Person对象,我们通过给Person对象添加KVO监听,来观察添加KVO前后的变化,见下图:
从打印结果我们可以看到:
- person1的类对象改变成了
NSKVONotifying_Person
- 通过输出方法的地址,我们发现添加KVO之后,实际调用的是
Foundation _NSSetIntValueAndNotify
下图是KVO实现的伪代码
我们发现,当对象通过KVO监听属性变化时,会利用RuntimeAPI动态生成一个子类,并且让instance对象的isa指向这个全新的子类
当修改instance对象的属性时,
- 会调用Foundation的
_NSSetXXXValueAndNotify
函数 willChangeValueForKey:
父类原来的setter
-
didChangeValueForKey:
内部会触发监听器(Oberser)的监听方法(observeValueForKeyPath:ofObject:change:context:
)
如何手动触发KVO?
手动调用
willChangeValueForKey:
和didChangeValueForKey:
直接修改成员变量会触发KVO么?
不会触发KVO
KVC
KVC的全称是Key-Value Coding,俗称“键值编码”,可以通过一个key来访问某个属性,常见的API如下:
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKey:(NSString *)key;
- (id)valueForKeyPath:(NSString *)keyPath;
- (id)valueForKey:(NSString *)key;