美文网首页
iOS KVO简介

iOS KVO简介

作者: 雪贝壳 | 来源:发表于2023-02-09 22:32 被阅读0次

    KVO简介

    KVO全称Key-Value-Observing,也就是键值监听,是苹果提供的一套通知机制。它允许一个对象监听另一个对象指定属性值的改变,被观察的对象属性发生改变时,会触发KVO的监听方法通知观察者。

    KVO的底层实现

    KVO是基于runtime机制,使用isa混写来实现的,一个对象首次被观察时,系统会创建一个派生类来重写setter方法,在setter方法内实现通知机制。被观察的对象的isa会被改变为派生类。当属性发生改变之前,willChangeValueForKeydii:被调用,继而调用didChangeValueForKey:,在此方法中再调用observeValueForKeyPath: ofObject: change: context:

    触发方式

    1.自动触发

    1)调用setter方法
    2)使用点语法
    3)使用KVC的setValue:forKey:、setValue:ForKeyPath:方法
    tips:直接修改成员变量不会触发KVO,因为没有触发setter方法,如:

    _name = @"jack";
    

    如果监听集合对象(NSArray、NSSet),需要通过 KVC 的 mutableArrayValueForKey: 或mutableSetValueForKey方法获得代理对象,并修改代理对象,当代理对象的内部对象发生改变时,才会触发 KVO。
    例如定义一个Person类如下:

    @interface Person : NSObject
    @property (nonatomic,copy) NSString * name;
    @property (nonatomic,strong) NSMutableArray *maryDatas;
    - (void)changeName;
    @end
    

    触发场景一,如下代码中data里的数据发生了变化即可触发(指针发生变化不会触发,如data=xxx)

    Person *person = [[Person alloc] init];
    person.maryDatas = [NSMutableArray arrayWithObject:@"1"];
    [person addObserver:self forKeyPath:@"maryDatas" options:NSKeyValueObservingOptionNew context:nil];
    NSMutableArray *data = [person mutableArrayValueForKey:@"maryDatas"];
    [data addObject:@"2"];//    [mary removeLastObject];
    

    触发场景二,调用person的setter方法

    Person *person = [[Person alloc] init];
    person.maryDatas = [NSMutableArray arrayWithObject:@"1"];
    [person addObserver:self forKeyPath:@"maryDatas" options:NSKeyValueObservingOptionNew context:nil];
    person.maryDatas = [NSMutableArray arrayWithObjecs:@"2"];
    //直接修改maryDatas里的数据不会触发
    //[person.maryDatas  addObject:@"2"];
    

    2.手动触发

    普通对象属性或成员变量手动调用willChangeValueForKey:和didChangeValueForKey:方法

    - (void)changeName{
        [self willChangeValueForKey:@"name"];
        _name = @"jack";
        [self didChangeValueForKey:@"name"];
    }
    

    NSArray对象调用:

    - (void)willChange:(NSKeyValueChange)changeKind valuesAtIndexes:(NSIndexSet *)indexes forKey:(NSString *)key;
    - (void)didChange:(NSKeyValueChange)changeKind valuesAtIndexes:(NSIndexSet *)indexes forKey:(NSString *)key;
    

    NSSet对象调用:

    - (void)willChangeValueForKey:(NSString *)key withSetMutation:(NSKeyValueSetMutationKind)mutationKind usingObjects:(NSSet *)objects;
    - (void)didChangeValueForKey:(NSString *)key withSetMutation:(NSKeyValueSetMutationKind)mutationKind usingObjects:(NSSet *)objects;
    

    3.自动触发控制

    重写以下方法可以控制是否自动触发KVO
    (1)+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key,可在方法内判断key来决定是否触发,此方法优先级最高。如果我们不希望外界监听name属性,其他属性正常监听,可以在Person类中如下操作:

    + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
        if ([key isEqualToString:@"name"]) {
            return NO;
        }
        return [super automaticallyNotifiesObserversForKey:key];
    }
    

    (2)方法名遵循规则+ (BOOL)automaticallyNotifiesObserversOf<Key>(Key为属性名,首字母大写),用来控制某一属性是否触发

    + (BOOL)automaticallyNotifiesObserversOfName {
        return NO;
    }
    
    + (BOOL)automaticallyNotifiesObserversOfMaryDatas {
        return YES;
    }
    

    相关文章

      网友评论

          本文标题:iOS KVO简介

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