KVO

作者: 今晚月色 | 来源:发表于2019-03-25 09:17 被阅读0次
    镇楼专用

    类的单个属性观察

    观察值的4中模式

    /**
     *  NSKeyValueObservingOptionNew     新值
     *  NSKeyValueObservingOptionOld     旧值
     *  NSKeyValueObservingOptionInitial 注册发送通知,改变时发送通知
     *  NSKeyValueObservingOptionPrior   改变之前发送通知,改变后发送通知
     */
    

    针对Person类里面的name属性进行观察

    [person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
    

    查看观察

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

    打印效果

    2019-03-22 09:20:16.875033+0800 KVO[1844:81256] {
        kind = 1;
        new = 0;
    }
    

    类的里面嵌套其他的属性观察

    观察Person里面Dog类的age,通过点语法直接监听

    [person addObserver:self forKeyPath:@"dog.age" options:NSKeyValueObservingOptionNew context:nil];
    

    输入结果

    2019-03-22 09:23:25.854859+0800 KVO[1876:84141] {
        kind = 1;
        new = 11;
    }
    

    一次性观察多个值

    例如观察Person里面的Dogagelevel,则在Person类中重新+ (NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key

    + (NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
        NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
        if ([key isEqualToString:@"dog"]) {
            NSArray *array = @[@"_dog.name", @"_dog.level"];
            keyPaths = [keyPaths setByAddingObjectsFromArray:array];
        }
        return keyPaths;
    }
    

    直接观察Dog

    [person addObserver:self forKeyPath:@"dog" options:NSKeyValueObservingOptionNew context:nil];
    

    打印结果

    2019-03-22 09:27:11.485240+0800 KVO[1929:87568] {
        kind = 1;
        new = "<Dog: 0x6000027c0b80>";
    }
    

    手动模式

    在Person类中重写+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key

    + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
        // 修改为手动模式
        return NO;
    }
    

    手动触发

    [self.person willChangeValueForKey:@"name"];
    [self.person didChangeValueForKey:@"name"];
    

    观察容器类

    需要利用KVC
    例如观察person中的array

     [[self.person mutableArrayValueForKey:@"array"] addObject:@"obj"];
    

    输出结果

    2019-03-22 11:02:13.996095+0800 KVO[5521:170395] {
        indexes = "<_NSCachedIndexSet: 0x600002216160>[number of indexes: 1 (in 1 ranges), indexes: (0)]";
        kind = 2;
        new =     (
            obj
        );
    }
    

    KVO的底层实现

    实质:观察值的setter方法
    通过runtime,新建一个子类继承于观察类(NSKVONotifing_类名),动态的修改了观察类的类型为子类的类型,在子类里面重写set方法,调用

    - (void)setName:(NSString *)name {
        [self willChangeValueForKey:@"name"];
        [super setName:name];
        [self didChangeValueForKey:@"name"];   
    }
    

    相关文章

      网友评论

          本文标题:KVO

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