KVO原理

2019-07-15  本文已影响0人  HChase

KVO的全称是Key-Value Observing,俗称“键值监听”,可以用于监听某个对象属性值的改变;

KOV的应用

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.person = [[Person alloc] init];
    self.person.age = 10;
    
    [self.person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
    
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.person.age = 20;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    
    NSLog(@"%@ ---- %@", keyPath, change);
}

原理

没有设置kvo的对象
设置kvo的对象

NSKVONotifying_×××的setter方法

上图中setAge:方法,内部调用了Foundation的_NSSetIntValueAndNotify方法;伪代码如下:

- (void)setAge:(int)age
{
    _NSSetIntValueAndNotify();
}

// 伪代码
void _NSSetIntValueAndNotify()
{
    [self willChangeValueForKey:@"age"];
    [super setAge:age];
    [self didChangeValueForKey:@"age"];
}

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

_NSSetIntValueAndNotify内部实现:

_NSSet***ValueAndNotify

上述例子是对 int 属性进行监听,所以对应着_NSSetIntValueAndNotify,不同类型的属性对应不同的_NSSet×××ValueAndNotify方法;

代码验证

在Person类中,重写willChangeValueForKeydidChangeValueForKey,查看执行状态;

@implementation Person
- (void)setAge:(int)age
{
    _age = age;
    
    NSLog(@"setAge:");
}

- (void)willChangeValueForKey:(NSString *)key
{
    [super willChangeValueForKey:key];
    
    NSLog(@"willChangeValueForKey");
}

- (void)didChangeValueForKey:(NSString *)key
{
    NSLog(@"didChangeValueForKey - begin");
    
    [super didChangeValueForKey:key];
    
    NSLog(@"didChangeValueForKey - end");
}
@end
2019-07-15 19:17:29.235721+0800 KVO[5624:7935847] willChangeValueForKey
2019-07-15 19:17:29.235880+0800 KVO[5624:7935847] setAge:
2019-07-15 19:17:29.235975+0800 KVO[5624:7935847] didChangeValueForKey - begin
2019-07-15 19:17:29.236946+0800 KVO[5624:7935847] age ---- {
    kind = 1;
    new = 20;
    old = 10;
}
2019-07-15 19:17:29.237125+0800 KVO[5624:7935847] didChangeValueForKey - end

可以看出监听回调确实是在didChangeValueForKey内部执行的。

源代码demo

上一篇 下一篇

猜你喜欢

热点阅读