KVO、KVC

作者: QYCD | 来源:发表于2021-04-01 17:33 被阅读0次

    KVO(Key Value Observing) 键值观察,苹果提供的一套事件通知机制

    KVO用于监听对象某个属性的改变,当被观察的属性的值发生变化时,会自动调用相应的方法。

    使用:
    1. 注册监听
      通过[addObserver:forKeyPath:options:context:]方法注册KVO,这样可以接收到keyPath属性的变化事件

    2. 监听方法
      通过方法[observeValueForKeyPath:ofObject:change:context:]实现KVO的监听

    3. 移除监听
      在不需要监听的时候,通过方法[removeObserver:forKeyPath:],移除监听

    //1. 注册监听
    [self.person addObserver:self forKeyPath:NSStringFromSelector(@selector(age)) options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
    
    //2. 监听实现
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
        NSLog(@"监听到%@的%@属性值改变了 %@", object, keyPath, change);
    }
    
    //3. 移除监听
    [self.person removeObserver:self forKeyPath:NSStringFromSelector(@selector(age))];
    
    KVO实现原理

    当一个对象使用了KVO监听,iOS系统会修改这个对象的isa指针,改为指向一个全新的通过Runtime(isa-swizzling)动态创建的子类,子类拥有自己的set方法实现,set方法实现内部会顺序调用willChangeValueForKey方法、原来的setter方法实现、didChangeValueForKey方法,而didChangeValueForKey方法内部又会调用监听器的observeValueForKeyPath:ofObject:change:context:监听方法

    通过在addObserver前后打断点可以得出以下结论:

    addObserver之前 person的isa指向Person类对象
    addObserver之后 isa指向NSKVONotifying_Person对象

    image.png image.png
    如何手动触发KVO

    被监听的属性的值被修改时,就会自动触发KVO。

    如果想要手动触发KVO,则需要我们自己调用willChangeValueForKey和didChangeValueForKey方法即可在不改变属性值的情况下手动触发KVO,并且这两个方法缺一不可

    //手动触发KVO 被监听的属性的值未发生改变 也触发KVO
    //以下方法缺一不可
    [self.person willChangeValueForKey:@"age"];
    [self.person didChangeValueForKey:@"age"];
    

    KVC(Key Value Coding) 键值编码,可以通过一个key来访问属性

    KVC提供了一种间接访问其属性或成员变量的机制,可以通过字符串来访问对应的属性方法或成员变量。

    常见API
    - (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
    
    - (void)setValue:(id)value forKey:(NSString *)key;
    
    - (id)valueForKeyPath:(NSString *)keyPath;
    
    - (id)valueForKey:(NSString *)key;
    
    setValue:forKey:原理
    1. 按照setKey、_setKey的顺序查找方法,找到方法则直接调用方法并赋值;
    2. 未找到方法则调用+ (BOOL)accessInstanceVariablesDirectly方法,若方法+ (BOOL)accessInstanceVariablesDirectly返回YES,则按照_key、_isKey、key、isKey的顺序查找成员变量,找到直接赋值,找不到则调用setValue:forUndefinedKey: 并抛出NSUnknownKeyException异常,若+ (BOOL)accessInstanceVariablesDirectly方法返回NO,则调用setValue:forUndefinedKey: 并抛出NSUnknownKeyException异常;
    valueForKey:原理
    1. 按照getKey、key、isKey、_key的顺序查找方法,找到则直接调用赋值;
    2. 若未找到,则查看+ (BOOL)accessInstanceVariablesDirectly方法的返回值,若返回YES,按照_key、_isKey、key、isKey的顺序查找成员变量,找到则取值,找不到则调用valueForUndefinedKey:并抛出NSUnknownKeyException异常;若返回NO,则调用valueForUndefinedKey:方法并抛出异常NSUnknownKeyException;

    通过KVC修改属性会触发KVO么
    会触发KVO,KVC在修改属性时,会调用willChangeValueForKey: 和 didChangeValueForKey:方法

    forKey与forKeyPath区别:
    forKey只能给当前对象的属性赋值
    forKeyPath可以给对象的属性的属性赋值

    valueForKey与valueForKeyPath区别:
    valueForKey只能获取当前对象属性的值
    valueForKeyPath可以获取当前对象属性的属性的值

    相关文章

      网友评论

          本文标题:KVO、KVC

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