程序员

十:KVO底层原理探究

2021-01-08  本文已影响0人  Mr姜饼

KVO介绍:

KVO,全称为Key-Value observing,中文名为键值观察,KVO是一种机制,它允许将其他对象的指定属性的更改通知给对象。

KVO的使用1(KeyPath):

1.添加观察者

[self.dog addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:NULL];

2.监听观察者

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

3.移除观察者:(必须一一对应,添加了,再释放的时候就需要移除)

[self.dog removeObserver:self forKeyPath:@"name" context:NULL];

KVO的使用2(context):

//定义context
static void *PersonNickContext = &PersonNickContext;
static void *PersonNameContext = &PersonNameContext;

//注册观察者
[self.person addObserver:self forKeyPath:@"nick" options:NSKeyValueObservingOptionNew context:PersonNickContext];
[self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:PersonNameContext];
    
    
//KVO回调
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    if (context == PersonNickContext) {
        NSLog(@"%@",change);
    }else if (context == PersonNameContext){
        NSLog(@"%@",change);
    }
}

KVO的自动触发和手动触发:

// 自动触发
+ (BOOL) automaticallyNotifiesObserversForKey:(NSString *)key{
    return YES;
}
//手动触发
+ (BOOL) automaticallyNotifiesObserversForKey:(NSString *)key{
    return NO;
}
- (void)setName:(NSString *)name{
    //手动开关
    [self willChangeValueForKey:@"name"];
    _name = name;
    [self didChangeValueForKey:@"name"];
}

KVO观察多个属性:

//1、合二为一的观察方法
+ (NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key{
    
    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
    if ([key isEqualToString:@"wallet"]) {
        NSArray *affectingKeys = @[@"rmb", @"dollars"];
        keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys];
    }
    return keyPaths;
}

//2、注册KVO观察
[self.person addObserver:self forKeyPath:@"wallet" options:(NSKeyValueObservingOptionNew) context:NULL];

//3、触发属性值变化
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    self.person.dollars += 1;
    self.person.rmb  += 1;
}

//4、移除观察者
- (void)dealloc{
    [self.person removeObserver:self forKeyPath:@"wallet"];
}

KVO观察可变数组:

kvo观察机制是基于 setValue 之上的,而可变数组在进行 addObject、removeObject等操作的时候,并不会触发 setValue 的方法,故此kvo会失效,这时候我们需要改进,在取我们的数组的时候要进行另一种方法去取

[[self mutableArrayValueForKey:@"dataSource"] addObject:@"ss"];

**KVO观察属性,但不会观察成员变量

属性比成员变量多一个set 和 get 方法,所以在改变其值的时候会触发kvo,但是成员变量并不会触发kvo


KCO底层实现原理探究:

1.注册KVO观察者后,观察对象的isa指针指向会发生改变
2.派生出来的类会重写原有类的set方法
3.当set方法监听到新值的变化,则回调监听,将监听结果告知观察者
4.移除观察者时,isa指针会重新指向原有类
5.派生类并不会随着移除操作而销毁,会一直存在于内存中

代码探究原理

image.png
上一篇 下一篇

猜你喜欢

热点阅读