美文网首页
KVC 和 KVO

KVC 和 KVO

作者: MrQun | 来源:发表于2022-02-16 22:22 被阅读0次

    KVC

    赋值时候方法和成员变量调用顺序

    1. 查看setKey:方法是否存在, 如果存在直接调用, 如果不存在进入下一步

    2. 查看_setKey:方法是否存在, 如果存在直接调用, 如果不存在进入下一步

    3. 查看+ (BOOL)accessInstanceVariablesDirectly方法的返回值, 默认返回YES

      1. YES: 可以访问成员变量, 进入下一步
      2. NO: 不可以访问成员变量, 同时调用- (void)setValue:(id)value forUndefinedKey:(NSString *)key方法, 如果方法不存在会抛出异常
    4. 调用成员变量:_key, _isKey, key, isKey(调用顺序, 从左到右, 只有发现有存在成员变量, 就不会在调用后续变量)

    5. 如果没有成员变量, 会调用- (void)setValue:(id)value forUndefinedKey:(NSString *)key方法, 如果方法不存在会抛出异常
      如果属性和成员变量同时存在, 就不会在访问属性了.

    取值时候方法和成员变量调用顺序

    1.判断是否有这几个方法: getKey, key, isKey, _key(从左到右, 如果有方法, 直接调用, 取值结束)如果没有进入下一步

    1. 调用+ (BOOL)accessInstanceVariablesDirectly查看是否可以访问成员变量. 默认YES
      1. YES: 可以访问成员变量, 进入下一步
      2. NO: 不可以访问成员变量, 判断是否实现- (id)valueForUndefinedKey:(NSString *)key方法, 实现时调用, 未实现报错
    2. 判断是否有这几个成员变量: _key, _isKey, key, isKey(从左到右, 如果有成员变量, 直接访问, 取值结束)如果没有这几个成员变量, 直接进入下一步

    4.判断是否实现- (id)valueForUndefinedKey:(NSString *)key方法, 实现时调用, 未实现报错
    使用KVC给属性或成员变量赋值时, 都会触发KVO, 系统会自动调用willChangeValueForKey:和didChangeValueForKey:两个方法

    KVO

    • 添加了观察者(KVO)的对象, 它的isa指针发生了改变, 指向了系统动态生成的子类NSKVONotifying_Person

    添加kvo后, 调用instance的set方法时候, 会调用Fundation的_NSSet*ValueAndNotify函数

    1. 调用willChangeValueForKey:
    2. 调用原来的setter实现
    3. 调用didChangeValueForKey:
      1. didChangeValueForKey:内部会调用observeValueForKeyPath:ofObject:change:context:

    直接修改对象的成员变量, 而不调用set方法, 将不会触发观察者的observeValueForKeyPath:ofObject:change:context:方法

    KVO 观察多个属性变化
     //1、合二为一的观察方法
        + (NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key{
            NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
            if ([key isEqualToString:@"distance"]) {
                NSArray *affectingKeys = @[@"speed", @"time"];
                keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys];
            }
            return keyPaths;
        }
        
        //2、注册KVO观察
        [self.person addObserver:self forKeyPath:@"distance" options:(NSKeyValueObservingOptionNew) context:NULL];
        
        //3、触发属性值变化
        - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
            self.person.speed += 10;
            self.person.time  += 1;
        }
        
        //4、移除观察者
        - (void)dealloc{
            [self.person removeObserver:self forKeyPath:@"distance"];
        }
    
    KVO可变数组的观察
    //1、注册可变数组KVO观察者
    self.person.dateArray = [NSMutableArray arrayWithCapacity:1];
        [self.person addObserver:self forKeyPath:@"dateArray" options:(NSKeyValueObservingOptionNew) context:NULL];
        
    //2、KVO回调
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
        NSLog(@"%@",change);
    }
    
    //3、移除观察者
    - (void)dealloc{
     [self.person removeObserver:self forKeyPath:@"dateArray"];
    }
    
    //4、触发数组添加数据
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    // -  改为下边写法   [self.person.dateArray addObject:@"1"];
        [[self.person mutableArrayValueForKey:@"dateArray"] addObject:@"1"];
    }
    

    相关文章

      网友评论

          本文标题:KVC 和 KVO

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