iOS 底层原理05: KVO, KVC

KVO

KVO全称是Key-Value Observing, 用于监听对象属性值的变化

KVO的使用
  1. 给一个对象的属性添加KVO
[p addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
复制代码
  1. 实现KVO的方法, 来监听属性值的变化
/** 
keyPath: 被观察的属性的key
object:  被观察的对象
change:  属性的改变对象
context: 上下文
*/
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    NSLog(@"监听到了%@的%@属性发生了改变", object, keyPath);
    NSLog(@"%@", change);
}
复制代码
KVO的原理
  1. 在iOS底层, 是通过isa-swizzling 来实现的. 当我们给对象A添加KVO时, 就会动态创建一个名字为 NSKVONotifying_A的类, 这个类继承自A的本类.
  2. 对象A的isa指针从A类指向NSKVONotifying_A, NSKVONotifying_A的superclass指针指向A类.
  3. 在NSKVONotifying_A中重写 setter方法, 在其中做一些KVO相关的处理
  4. 当我们修改A对象属性时, 会通过isa指针找到NSKVONotifying_A类中的方法列表, 执行NSKVONotifying_A重写过的setter方法, 来实现KVO的处理

我们可以通过打印isa指针来郑明这一点
image.png

KVO如何重写setter方法

通过上边的分析, 我们可以猜测KVO重写的setter方法可能为:

- (void)setName:(NSString *)name {
    [self willChangeValueForKey:@"name"];
    // 这里会进行修改name的值
    [self didChangeValueForKey:@"name"]; // 触发 observeValueForKeyPath: 方法, 回调给观察者
}
复制代码

KVC

KVC全称是Key-Value Coding, 可以通过字符串key来访问对象的某个属性

KVC的使用

常用的KVCAPI有:

- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKey:(NSString *)key;
- (id)valueForKeyPath:(NSString *)keyPath;
- (id)valueForKey:(NSString *)key; 
复制代码
setValue:forKey: 查找的过程
  1. 根据key查找: setKey, _setKey方法, 调用setter方法
  2. 查看accessInstanceVariablesDirectly函数的返回值,如果是NO, 进行第4步.(默认是YES)
  3. 查找_key、_isKey、key、isKey的成员变量, 进行赋值
  4. 调用setValue:forUndefinedKey:, 并抛出异常NSUnknownKeyException
valueForKey: 查找的过程
  1. 查找getKey、key、 isKey、_key方法, 调用getter方法
  2. accessInstanceVariablesDirectly函数的返回值,如果是NO, 进行第4步.(默认是YES)
  3. 查找_key、_isKey、key、isKey的成员变量, 直接取值
  4. 调用valueForUndefinedKey:, 并抛出异常NSUnknownKeyException

KVC与KVO

  1. 我们直接, 给一个属性赋值可以触发KVO, 那么通过KVC可以么? 可以

image.png

  1. 直接给对象的成员变量赋值, 可以触发KVO么? 不可以

image.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享