KVO相关

作者: 赖晓嘉LMT | 来源:发表于2018-06-07 17:42 被阅读0次

    KVO的实现原理:    核心是重写子类的set方法进行监听

    具体是:当某一个类在注册监听的时候,系统会动态(1)创建一个继承此类的一个子类(2),并用isa指针(3)指向该子类,当我们改变某一个属性值时,KVO会重写子类的 setter 方法(4),setter 方法会负责在调用原 setter 方法之前和之后,通知所有观察对象属性值的更改情况

    (1)C语言创建某一个类的子类:

    //动态添加一个类

    NSString *oldClassName = NSStringFromClass([self class]);

    NSString *newClassName = [@"NSKVONotifying_" stringByAppendingString:oldClassName];

    const char * newName = [newClassName UTF8String];

    Class myclass = objc_allocateClassPair([self class],

    newName, 0);

    注:objc_allocateClassPair(Class superclass,constchar*name, size_t extraBytes)   添加类 superclass 类是父类 name 类的名字 size_t 类占的空间

    (2)当观察对象A时,KVO机制动态创建一个新的名为:NSKVONotifying_A的新类,该类继承自对象A的本类.

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

    (3)isa指针的作用:是一个Class 类型的指针. 每个实例对象有个isa的指针,他指向对象的类,而Class里也有个isa的指针, 指向meteClass(元类)。元类保存了类方法的列表。当类方法被调用时,先会从本身查找类方法的实现,如果没有,元类会向他父类查找该方法。同时注意的是:元类(meteClass)也是类,它也是对象。元类也有isa指针,它的isa指针最终指向的是一个根元类(root meteClass).根元类的isa指针指向本身,这样形成了一个封闭的内循环。

    (4)子类setter方法剖析:KVO 的键值观察通知依赖于 NSObject 的两个方法:willChangeValueForKey:和 didChangevlueForKey:,在存取数值的前后分别调用 2 个方法:

    被观察属性发生改变之前,willChangeValueForKey:被调用,通知系统该 keyPath 的属性值即将变更;当改变发生后, didChangeValueForKey: 被调用,通知系统该 keyPath 的属性值已经变更;之后, observeValueForKey:ofObject:change:context: 也会被调用。且重写观察属性的 setter 方法这种继承方式的注入是在运行时而不是编译时实现的

    注意:观察者观察的是属性,只有遵循 KVO 变更属性值的方式才会执行 KVO 的回调方法,例如是否执行了 setter 方法、或者是否使用了 KVC 赋值。

    如果赋值没有通过 setter 方法或者 KVC,而是直接修改属性对应的成员变量,例如:仅调用 _name = @"newName",这时是不会触发 KVO 机制,更加不会调用回调方法的。

    所以使用 KVO 机制的前提是遵循 KVO 的属性设置方式来变更属性值。

    附加:

    苹果为什么要用子类(就是C语言创建的那个子类)监听setter方法,而不用category类(Person+KVO)呢?

    原因是当你用分类监听setter方法的时候,Person类中setter方法就不会走了,这样不好,所以苹果使用了子类监听setter方法。

    KVC 与 KVO 的不同?

    KVC(键值编码),即 Key-Value Coding,一个非正式的 Protocol,使用字符串(键)访问一个对象实例变量的机制。而不是通过调用 Setter、Getter 方法等显式的存取方式去访问。

    KVO(键值监听),即 Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,对象就会接受到通知,前提是执行了 setter 方法

    KVO和 notification(通知)的区别?

    notification 比 KVO 多了发送通知的一步。

    两者都是一对多,但是对象之间直接的交互,notification 明显得多,需要notificationCenter 来做为中间交互。而 KVO 如我们介绍的,设置观察者->处理属性变化,至于中间通知这一环,则隐秘多了,只留一句“交由系统通知”

    notification 的优点是监听不局限于属性的变化,还可以对多种多样的状态变化进行监听,监听范围广,例如键盘、前后台等系统通知的使用也更显灵活方便。

    KVO 和线程

    KVO 行为是同步的,并且发生与所观察的值发生变化的同样的线程上。没有队列或者 Run-loop 的处理.所以不是线程安全的,当我们试图从其他线程改变属性值的时候我们应当十分小心,除非能确定所有的观察者都用线程安全的方法处理 KVO 通知。通常来说,我们不推荐把 KVO 和多线程混起来。如果我们要用多个队列和线程,我们不应该在它们互相之间用 KVO

    详细自定义kvo传送门
    [导致kvo崩溃的点](https://www.jianshu.com/p/a3acab9dfc4a)

    相关文章

      网友评论

          本文标题:KVO相关

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