如何手动触发一个 value 的 KVO?

作者: iOS猿_员 | 来源:发表于2019-01-29 20:59 被阅读73次

    原文:iOS面试题大全

    KVC,即是指 NSKeyValueCoding,一个非正式的 Protocol,提供一种机制来间接访问对象的属性。KVO 就是基于 KVC 实现的关键技术之一。

    键值观察通知依赖于 NSObject 的两个方法: willChangeValueForKey:didChangevlueForKey:。在一个被观察属性发生改变之前,willChangeValueForKey: 一定会被调用,这就会记录旧的值。而当改变发生后,observeValueForKey:ofObject:change:context:didChangeValueForKey:也会被调用。如果可以手动实现这些调用,就可以实现“手动触发”了。

        @property (nonatomic, strong) NSDate *now;
        - (void)viewDidLoad {
           [super viewDidLoad];
           _now = [NSDate date];
           [self addObserver:self forKeyPath:@"now" options:NSKeyValueObservingOptionNew context:nil];
           NSLog(@"1");
           [self willChangeValueForKey:@"now"]; // 手动触发 self.now 的 KVO,必写。
           NSLog(@"2");
           [self didChangeValueForKey:@"now"]; // 手动触发 self.now 的 KVO,必写。
           NSLog(@"4");
        }
        - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
           NSLog(@"3");
        }
    

    打印顺序是:1 2 3 4。从这里看顺序似乎是 wilChangeValueForKey:observeValueForKeyPath:ofObject:change:context:didChangeValueForKey:。其实,实际情况是:wilChangeValueForKey:先调用,接着是调用 didChangeValueForKey:,在 didChangeValueForKey: 内部调用了 observeValueForKeyPath:ofObject:change:context:。你可以注释掉[self didChangeValueForKey:@"now"];试试。

    但是平时我们一般不会这么干,我们都是等系统去“自动触发”。“自动触发”的实现原理:

    比如调用 setNow: 时,系统还会以某种方式在中间插入 wilChangeValueForKey:didChangeValueForKey:observeValueForKeyPath:ofObject:change:context:的调用。

    大致表现如下:

        - (void)setNow:(NSDate *)aDate {
           [self willChangeValueForKey:@"now"];
           [super setValue:aDate forKey:@"now"];
           [self didChangeValueForKey:@"now"];
        }
    

    Apple 使用了 isa 混写(isa-swizzling)来实现 KVO,这种继承和方法注入是在运行时而不是编译时实现的。这就是正确命名如此重要的原因。只有在使用 KVC 命名约定时,KVO 才能做到这一点。KVO 在实现中通过 isa 混写(isa-swizzling)把这个对象的 isa 指针(isa 指针告诉 Runtime 系统这个对象的类是什么)指向这个新创建的子类,对象就神奇的变成了新创建的子类的实例。Apple 还重写、覆盖了 -class 方法并返回原来的类,企图欺骗我们:这个类没有变,就是原本那个类。

    相关文章

      网友评论

        本文标题:如何手动触发一个 value 的 KVO?

        本文链接:https://www.haomeiwen.com/subject/lpdfsqtx.html