KVO - 键值监听

40 阅读1分钟

🚩 KVO是利用runtime的特性动态生成观察对象的子类,然后重写被观察对象的属性的set方法

可用于监听某个对象属性值的改变

1 对Person对象的age属性建立监听

// 如何设置属性的KVO
@property (nonatomic, strong) Person *person1;
- (void)viewDidLoad { 
    [super viewDidLoad]; 
    _person1 = [[Person alloc] init];
    _person1.age = 32; 
    // 需要返回的数据,新的值 | 旧的值 
    NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld; 
    // 对person1属性age设置监听,附带信息:@"附加信息" 
    [self.person1 addObserver:self forKeyPath:@"age" options:options context:@"附加信息"]; 
}

2 实现监听方法,当age被设置时,该方法将被掉用

// person1.age改变时会调用这里 
-(void)observeValueForKeyPath:(NSString *)keyPath 
                     ofObject:(id)object 
                       change:(NSDictionary<NSKeyValueChangeKey,id> *)change 
                       context:(void *)context { 
    NSLog(@"keyPath: %@, object: %@;\nchange: %@, context: %@", keyPath, object, change, context); 
}

3 最后,当不需要监听时,适时移除监听

// 监听者销毁时移除相应的监听
-(void)dealloc { 
    [_person1 removeObserver:self forKeyPath:@"age"]; 
}

KVO的本质(内部实现)

打印对象isa地址、name类名

在设置监听前后打印person1,2的isa地址。发现person1在设置完监听后地址发生了改变;在设置监听前后打印person1,2的类名。发现person1在设置完监听后改变为:NSKVONotifying_Person image.png

小结

可以看出,程序在runtime的时候动态生成了 NSKVONotifying_PersonNSKVONotifying_Person 继承于 Person,当改变 age 的值时,即调用 setAge:方法。NSKVONotifying_Person 重写了 setAge:并做了其他事情。具体做了那些事可以猜测: image.png didChangeValueForKey:内部会调用observerobserveValueForKeyPath:ofObject:change:context:方法

KVO是利用runtime的特性动态生成观察对象类的子类,然后重写被观察对象的属性的set方法。

如何手动触发KVO?

手动调用willChangeValueForKey:didChangeValueForKey: 。只调用didChangeValueForKey:是无法触发的。