美文网首页
KVO底层原理分析

KVO底层原理分析

作者: iOS扫地僧 | 来源:发表于2018-07-04 16:22 被阅读0次

一、 KVO内部实现原理

  • KVO是基于 runtime机制实现的,使用了isa 混写(isa-swizzling

  • 当某个类的属性对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter 方法。派生类在被重写的setter方法内实现真正的通知机制

  • 如果原类为Person,那么生成的派生类名为NSKVONotifying_Person (查看方法后面讲解)

  • 每个类对象中都有一个isa指针指向当前类,当一个类对象的第一次被观察,那么系统会偷偷将isa指针指向动态生成的派生类,从而在给被监控属性赋值时执行的是派生类的setter方法

  • 键值观察通知依赖于NSObject 的两个方法: willChangeValueForKey:didChangevlueForKey:;在一个被观察属性发生改变之前, willChangeValueForKey:一定会被调用,这就 会记录旧的值。而当改变发生后,didChangeValueForKey:会被调用,继而 observeValueForKey:ofObject:change:context: 也会被调用。

  • 补充:KVO的这套实现机制中苹果还偷偷重写了class方法,让我们误认为还是使用的当前类,从而达到隐藏生成的派生类

二、论证产生的子类

Book类
#import <Foundation/Foundation.h>

@interface Book : NSObject

@property (nonatomic, copy) NSString *price;

@property (nonatomic, copy) NSString *name;

@end

重写description方法便于观察产生的子类

#import "Book.h"
#import <objc/runtime.h>

@implementation Book

- (NSString *)description {
    NSLog(@"object address : %p \n", self);
    Class objectMethodClass = [self class];
    Class objectRuntimeClass = object_getClass(self);
    Class superClass = class_getSuperclass(objectRuntimeClass);
    NSLog(@"objectMethodClass : %@, ObjectRuntimeClass : %@, superClass : %@ \n", objectMethodClass, objectRuntimeClass, superClass);
    return @"";
}
@end
初始化调用
- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.abook = [[Book alloc]init];
    NSLog(@"初始化%@",self.abook);
    
    [self.abook addObserver:self forKeyPath:@"price" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
    [self.abook addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
}
打印结果如下
image.png

注意:这是在绑定观察者模式之前的初始化调用,此时还没有被观察,此时并没有产生子类

触发监听调用
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"之前%@",self.abook);
    //触发监听
    [self.abook setValue:@"book" forKey:@"name"];
    [self.abook setValue:@"34" forKey:@"price"];
}
打印结果如下
image.png

注意:这里写了一个简单的触发事件,此时可以观察到,已经产生了一个新的类:NSKVONotifying_Book也可以观察到它的父类是Book

附加知识

有些时候程序逻辑的需要,一个类想要实现手动的change notification发送,则必须重写NSObject实现的automaticallyNotifiesObserversForKey:方法,并对需要实现手动发送的key返回NO,其余则调用super。

对price属性关闭自动发送

+ (BOOL) automaticallyNotifiesObserversForKey:(NSString *)key {
    if ([key isEqualToString:@"price"]) {
        return NO;
    }
    return [super automaticallyNotifiesObserversForKey:key];
}

对price属性实现手动的change notification发送

- (void)setPrice:(NSString *)price
{
    [self willChangeValueForKey:@"price"];
    _price = price;
    [self didChangeValueForKey:@"price"];
}

本文部分内容转载自:https://www.jianshu.com/p/829864680648

相关文章

网友评论

      本文标题:KVO底层原理分析

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