OC

KVO的本质

Posted on 2020-12-24,2 min read

简单了解KVO底层的实现逻辑

示例代码

OC当中的KVO使用起来很简单,简单3个步骤就可以完成对一个对象的成员变量的监听;
假如我们想监听Persen对象的age属性:

// 1.给Person对象添加KVO监听
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
[self.person addObserver:self forKeyPath:@"age" options:options context:@"123"];

// 2. 监听对象的属性发生改变时的回调函数
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{}

// 3.移除监听
[self.person removeObserver:self forKeyPath:@"age"];

KVO实现的本质

  • 依然以Persen对象为例,正常情况下,self.person这个实例对象的isa指针,指向的应该是Person这个类对象;但是当给其添加KVO监听后,会在self.person这个instance对象和Person class对象之间,生成一个Person class的子类NSKVONotifying_Person;这时实例对象的isa指针,就会更改为指向NSKVONotifying_Person这个class对象;

    NSKVONotifying_Person是Runtime动态创建的一个类,是Person的子类; 其内部包含class方法,返回值可能为[Person class]父类class

  • 那么NSKVONotifying_Person是如何实现监听的过程呢?

// 以下均为伪代码,方便理解

- (void)setAge:(int)age {
    // 在执行set方法时,会调用c函数中的下面这个方法
    _NSSetIntValueAndNotify(); // 当然不仅仅有int的方法,char、long long、double...都有
} 

void _NSSetIntValueAndNotify() {
    [self willChangeVlaueForKey:@"age"];
    [super setAge:age]; // 调用父类Person的setAge方法
    [self didChangeValueForKey:@"age"];
}

- (void)didChangeValueForKey:(NSString *)key {
    // 通知监听器,属性值发生了改变
    [observer observeValueForKeyPath: key ofObject:self change:change context:nil];
}

下一篇: OC对象的本质→

loading...