iOS KVO原理的探究

使用KVO分三个步骤:

1 通过addObserver:forKeyPath:options:context:方法注册观察者,观察者可以接收keyPath属性的变化事件
    Observer 被观察者对象   keyPath 需要观察的属性
    options 参数
        NSKeyValueObservingOptionNew 接收新值,默认为接收新值
        NSKeyValueObservingOptionOld   接收旧值
        NSKeyValueObservingOptionInitial 在注册时立即接收一次回调 在改变时也会发送通知
        NSKeyValueObservingOptionPrior 改变之前发一次 改变之后发一次
     Context  任意参数  可以用来标记 跟回调的context相对应   
2 在观察者中实现observeValueForKeyPath:ofObject:change:context: 方法 当keyPath属性发生改变后,KVO回调这个方法来通知观察者。
    change里面的kind
          NSKeyValueChangeSetting   //set
          NSKeyValueChangeInsertion //容器类 插入的
          NSKeyValueChangeRemoval   //容器类 remove
          NSKeyValueChangeReplacement //重新替换    
3 当观察者不需要监听时,可以调用removeObserver:forKeyPath:方法将Kvo移除。 必须在观察者消失之前移除 否则会Crash

在调用addObserver方法后,KVO并不会对观察者进行强引用 所以要注意观察者的生命周期 否则会到这观察者被释放带来的Crash

KVO有两种触发模式 默认的是自动模式 下来我们说说手动模式

这个方法默认返回YES 返回yes时就是自动模式 返回NO时 就是手动模式  key 是要观察的属性 可以根据key进行动态调整 
> 坑-> 不要全部返回NO 要根据key动态返回  不然 瞬干爆炸 头皮发麻 
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key;

当调整为手动模式的时候 改变被监听的对象的时候 是不会被监听到的(因为需要手动调用)

    [objc willChangeValueForKey:@"keyPath"];
    objc.xxxx = xxx;(没有这句话的时候 观察者也会接收到回调)
    [objc didChangeValueForKey:@"keyPath"]; 

KVO的属性依赖 关联关系

//关联关系
+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
    NSString *objKey;
    if ([key isEqualToString:objKey]) {
        keyPaths = [[NSSet alloc]initWithObjects:@"需要关联key1",@"需要关联key1", nil];
    }
    return keyPaths;
}
这样关联了以后 被关联的值发生改变以后也会被key的观察者监听到 

kvo如何观察容器类
容器类:数组 字典。。。

当你需要改变容器类的值得时候通过这种法获取容器 然后进行改值
 NSMutableArray *array = [objc mutableArrayValueForKey:@"key"];
[ array addObjc:xx]
 这个 array 和你之前的array已经不一样了 所以他会被监听到
 其他的容器类同上 自己探究

KVO的底层原理 —>底层没有开元 一切源于网络

  1. 创建一个该对象的子类
  2. 重写set方法
  3. 修改外界的isa指针
[objc addObserver:self forKeyPath:@"page" options:NSKeyValueObservingOptionNew context:nil];
当调用这个方法之后 objc的isa指针不会再指向objc 而是指向 NSKVONotyfing_objc
系统在这个方法里创建了一个继承与objc 的子类并且在里面重写了 keyPath的set方法 当keyPath属性发生变化时 会回调到observeValueForKeyPath:ofObject:change:context: 方法里面

你可能感兴趣的:(oc---细节)