美文网首页
ios KVO及实现原理

ios KVO及实现原理

作者: 赵哥窟 | 来源:发表于2018-09-04 10:13 被阅读3次

    概述
    KVO全称KeyValueObserving,是苹果提供的一套事件通知机制。允许对象监听另一个对象特定属性的改变,并在改变时接收到事件。由于KVO的实现机制,所以对属性才会发生作用,一般继承自NSObject的对象都默认支持KVO。

    KVO和NSNotificationCenter都是iOS中观察者模式的一种实现。区别在于,相对于被观察者和观察者之间的关系,KVO是一对一的,而不一对多的。KVO对被监听对象无侵入性,不需要修改其内部代码即可实现监听。

    KVO可以监听单个属性的变化,也可以监听集合对象的变化。通过KVC的mutableArrayValueForKey:等方法获得代理对象,当代理对象的内部对象发生改变时,会回调KVO监听的方法。集合对象包含NSArray和NSSet。

    基础使用
    使用KVO分为三个步骤:
    1.注册观察者,指定被观察对象的属性

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

    2.在观察者中实现以下回调方法

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

    3.当观察者不需要监听时

     [person removeObserver:self forKeyPath:@"name"];
    

    实现原理
    KVO是通过isa-swizzling技术实现的。在运行时根据原类创建一个中间类,这个中间类是原类的子类,并动态修改当前对象的isa指向中间类。并且将class方法重写,返回原类的Class。

    测试代码

    Person *person = [Person new];
    person.name = @"old";
    NSLog(@"before Class Name:%s",object_getClassName(person));
    [person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
     NSLog(@"after Class Name:%s",object_getClassName(person));
    

    控制台输出

    2018-09-04 09:59:09.531941+0800 KOVAndKVCDemo[36344:19883033] before Class Name:Person
    2018-09-04 09:59:09.532317+0800 KOVAndKVCDemo[36344:19883033] after Class Name:NSKVONotifying_Person
    

    上面的原理结合代码原理可以这样理解:
    当观察对象Person时,KVO机制动态创建一个新的名为: NSKVONotifying_Person的新类,该类继承自对象Person的本类,且KVO为NSKVONotifying_Person重写观察属性的setter 方法,setter 方法会负责在调用原 setter 方法之前和之后,通知所有观察对象属性值的更改情况。

    怎么理解setter 方法会负责在调用原 setter 方法之前和之后,类似看如下代码

    -(void)setName:(NSString *)name
    {
        [self willChangeValueForKey:@"name"];    //KVO在调用存取方法之前总调用
        [super name forKey:@"name"]; //调用父类的存取方法
        [self didChangeValueForKey:@"name"];     //KVO在调用存取方法之后总调用
    }
    

    NSKVONotifying_Person类剖析
    在这个过程,被观察对象的 isa 指针从指向原来的Person类,被KVO机制修改为指向系统新创建的子类NSKVONotifying_Person类,来实现当前类属性值改变的监听;

    子类setter方法剖析
    KVO的键值观察通知依赖于 NSObject 的两个方法:willChangeValueForKey:和 didChangevlueForKey:,在存取数值的前后分别调用2个方法:
    被观察属性发生改变之前,willChangeValueForKey:被调用,通知系统该 keyPath 的属性值即将变更;当改变发生后, didChangeValueForKey: 被调用,通知系统该 keyPath 的属性值已经变更;之后, observeValueForKey:ofObject:change:context: 也会被调用。且重写观察属性的setter 方法这种继承方式的注入是在运行时而不是编译时实现的。

    如何手动实现KVC?

     [person willChangeValueForKey:@"name"];
      person.name = @"Alex";
     [person didChangeValueForKey:@"name"];
    

    demo:https://github.com/destinyzhao/KOVAndKVCDemo

    相关文章

      网友评论

          本文标题:ios KVO及实现原理

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