iOS 代理、通知、KVO

作者: num_one | 来源:发表于2019-02-21 14:43 被阅读84次

    1.代理delegate

    delegate 代理流程 代理方与委托方的关系

    2.通知NSNotification

    通知 通知流程 通知实现机制

    3.KVO

    KVO的实现依赖于 Objective-C 强大的 Runtime,当观察某对象 A 时,KVO 机制动态创建一个对象A当前类的子类,并为这个新的子类重写了被观察属性 keyPathsetter 方法。setter 方法随后负责通知观察对象属性的改变状况。
    Apple 使用了 isa-swizzling 来实现 KVO 。当观察对象A时,KVO机制动态创建一个新的名为:NSKVONotifying_A的新类,该类继承自对象A的本类,且 KVO 为 NSKVONotifying_A重写观察属性的setter 方法,setter 方法会负责在调用原 setter 方法之前和之后,通知所有观察对象属性值的更改情况。

    NSKVONotifying_A 类剖析

    NSLog(@"self->isa:%@",self->isa);  
    NSLog(@"self class:%@",[self class]);  
    

    在建立KVO监听前,打印结果为:

    self->isa:A
    self class:A
    

    在建立KVO监听之后,打印结果为:

    self->isa:NSKVONotifying_A
    self class:A
    

    在这个过程,被观察对象的 isa指针从指向原来的 A 类,被KVO 机制修改为指向系统新创建的子类NSKVONotifying_A 类,来实现当前类属性值改变的监听;
    所以当我们从应用层面上看来,完全没有意识到有新的类出现,这是系统“隐瞒”了对 KVO 的底层实现过程,让我们误以为还是原来的类。但是此时如果我们创建一个新的名为NSKVONotifying_A的类,就会发现系统运行到注册 KVO 的那段代码时程序就崩溃,因为系统在注册监听的时候动态创建了名为 NSKVONotifying_A 的中间类,并指向这个中间类了。

    子类setter方法剖析

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

    - (void)setName:(NSString *)newName { 
          [self willChangeValueForKey:@"name"];    //KVO 在调用存取方法之前总调用 
          [super setValue:newName forKey:@"name"]; //调用父类的存取方法 
          [self didChangeValueForKey:@"name"];     //KVO 在调用存取方法之后总调用
    }
    
    KVO图解及代码实现
    KVO KVO原理 KVO重写了setter方法 代码1 代码2
    KVO可以监听到点语法、KVC,通过成员变量赋值不能被KVO监听到。

    3.区别

    1.代理使用代理模式,通知、KVO使用观察者模式
    2.传递方式:代理是1对1,通知是1对n。
    3.KVO底层使用isa混写实现的(Runtime)。

    👏👏👏欢迎大家加入群组(IT_大前端技术交流群),技术交流群
    
    IT_大前端技术交流群

    相关文章

      网友评论

        本文标题:iOS 代理、通知、KVO

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