KVC、KVO的底层原理

------------------KVC---------------------

KVC是一种通过字符串来访问实例对象属性或变量的机制,使用最多的是用来字典转模型。利用runtime获取对象的所有成员变量, 再根据kvc键值赋值,进行字典转模型
当给对象发送setValue:forKey 消息时要判断对象是否存在key所对应的属性,如果有,直接赋值;如果没有就调用undefinedKey(默认崩溃,需要重写)

setValue:forKey的调用顺序
  1. 首先会按照setkey,_setKey顺序找方法
  2. 如果没有那么按 _key, _isKey,key, iskey的顺序搜索成员变量名
  3. 如何还没找到就调用setValue:forUndefinedKey:(默认崩溃,需要重写)
ValueForKey的调用顺序
  1. 首先会按照getKey, key, isKey,_key顺序找方法
  2. 如果没有那么按 _key, _isKey,key, iskey的顺序搜索成员变量名
  3. 如何还没找到就调用valueForUndefinedKey
setValueForKey:valueForKey内部查找.png

------------------KVO---------------------

KVO是观察者模式的实现,使用了ISA混写技术
当被监听对象某个属性发生改变时,监听该属性值变化的对象可以接受到通知,然后通过kvo提供的系统的方法响应一些操作,有利于两个类间的解耦

原理

KVO是基于runtime机制实现的,某个对象被观察时,runtime会在运行时动态创建一个新的继承被监听类的子类(NSKVONotifying_ 开头)
1、然后将被监听类的对象的isa指针指向子类类对象;
2、并重写子类被观察属性的setter 方法,(这个重写是在运行时而不是编译时实现的,而且是KVO本质);当被监听对象的属性改变时,会触发set方法,但这个方法被重写了,并且在内部调用了didChangeValueForKey方法从而触发通知机制

KVO机制的特点和触发前提

  • 修改的是属性
  1. 通过setter方法直接修改
  2. 通过 KVC (内部会调用setter方法,从而触发KVO)
  • 修改的是成员变量
    KVC修改成员变量触发KVO.png
  1. KVC修改内部会触发KVO
  2. 手动触发
KVO图形.png
KVO描述.png

KVO使用步骤

  1. 注册观察者,实施监听
[self.p1 addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
  1. 在回调方法中处理属性发生的变化
// 这个方法时属于 NSObject 类的,任何对象都可以作为观察者
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
        NSLog(@"监听到了%@的%@属性发生了改变", object, keyPath);
        NSLog(@"%@", change);
    }
  1. 移除观察者
[p1 removeObserver:self forKeyPath:@"name"];
  • 子类重写被观察属性的setter方法的内部实现
- (void)setName:(NSString *)name
{
    
    [self willChangeValueForKey:@"age"];
   [super setName:name];
    [self didChangeValueForKey:@"age"];
// 这两个方法底层会调用observer的- (void)observeValueForKeyPath: ofObject: change: context:这个方法
}

拓展

  • KVO和notification(通知)的区别?
  1. 两者都是一对多
  2. notification的优点是监听不局限于属性的变化,还可以对多种多样的状态变化进行监听,监听范围广
  • KVO与delegate的不同?

KVO和NSNotification 都是负责发送接收通知,剩下的事情由系统处理,所以不用返回值; delegate 则需要代理联系
delegate一般是一对一,而这两个可以一对多

另外需要注意的是,由于KVO这种继承方式的注入是在运行时而不是编译时实现的,如果给定的实例没有观察者,那么KVO不会有任何开销,因为此时根本就没有KVO代码存在。但是即使没有观察者,委托和NSNotification还是得工作,这也是KVO此处零开销观察的优势

总结

对比其他的回调方式,KVO机制的运用的实现,更多的由系统支持,相比notification、delegate等更简洁些,并且能够提供观察属性的最新值以及原始值;但是相应的在创建子类、重写方法等等方面的内存消耗是很巨大的

1、异步:监听通知 主线程:发出通知 接收通知代码在主线程
2、主线程:监听通知 异步:发出通知 接收通知代码在异步
总结:接收通知代码 由 发出通知线程决定, KVO也一样

参考

你可能感兴趣的:(KVC、KVO的底层原理)