KVO实现原理

2020-09-24  本文已影响0人  小胖纸啦
    Person *p1 = [[Person alloc] init];
    Person *p2 = [[Person alloc] init];
    
    // 监听前后对象的类对象有没有变化
    id class1 = object_getClass(p1);
    id class2 = object_getClass(p2);
    
    IMP imp1 = [p1 methodForSelector:@selector(setName:)];
    IMP imp2 = [p2 methodForSelector:@selector(setName:)];
    
    id superClass1 = class_getSuperclass(class1);
    id superClass2 = class_getSuperclass(class2);
    
    NSLog(@"KVO监听前:p1:%@ p2:%@", p1, p2);
    
    NSLog(@"KVO监听前:p1.class:%@ p2.class:%@",class1, class2);
    
    NSLog(@"KVO监听前:imp1:%p imp2:%p",imp1, imp2);
    
    NSLog(@"KVO监听前:superclass1:%@ superclass2:%@",superClass1, superClass2);
    
    [p1 addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
    
    class1 = object_getClass(p1);
    class2 = object_getClass(p2);
    
    imp1 = [p1 methodForSelector:@selector(setName:)];
    imp2 = [p2 methodForSelector:@selector(setName:)];
    
    superClass1 = class_getSuperclass(class1);
    superClass2 = class_getSuperclass(class2);
    
    NSLog(@"KVO监听后:p1:%@ p2:%@",p1, p2);
    
    NSLog(@"KVO监听后:p1.class:%@ p2.class:%@",class1, class2);
    
    NSLog(@"KVO监听后:imp1:%p imp2:%p",imp1, imp2);
    
    NSLog(@"KVO监听后:superclass1:%@ superclass2:%@",superClass1, superClass2);

    NSString *methodList1 = [self printPersonMethods:class1];
    NSString *methodList2 = [self printPersonMethods:class2];
    NSLog(@"KVO监听后:methodlist1:%@ \n methodlist2:%@",methodList1, methodList2);
// 没有任何变化
KVO监听前:p1:<Person: 0x6000036287f0> p2:<Person: 0x6000036287d0>
KVO监听后:p1:<Person: 0x6000036287f0> p2:<Person: 0x6000036287d0>

// p1.class: NSKVONotifying_Person p2.class: Person
// p1的类对象发生改变
KVO监听前:p1.class:Person p2.class:Person
KVO监听后:p1.class:NSKVONotifying_Person p2.class:Person

// p1的setName:方法实现IMP指针发生变化
KVO监听前:imp1:0x104e50db0 imp2:0x104e50db0
KVO监听后:imp1:0x10512198b imp2:0x104e50db0

// superclass1:Person superclass2:NSObject
// 所以NSKVONotifying_Person是一个 Person 子类(苹果Runtime动态创建Person的一个子类)
KVO监听前:superclass1:NSObject superclass2:NSObject
KVO监听后:superclass1:Person superclass2:NSObject
methodlist1:[
setName:
class
dealloc
_isKVOA
] 
 methodlist2:[
.cxx_destruct
name
setName:
]
// 打印结果可以看出都有 setName:方法
// 但是 methodList1里面重写了setName: class 和 dealloc 方法,而且还多了一个_isKVOA方法
// 重写setName: 是为了在该方法里面调用_NSSetObjectValueAndNotify()方法
// 重写class方法是为了返回Person类
// 重写dealloc方法是为了向外界隐藏NSKVONotifying_Person子类的存在
// 所以这就是我们开始直接打印p1和p2都是Person类的原因
- (NSString *) printPersonMethods:(id)obj {

    unsigned int count = 0;
    Method *methods = class_copyMethodList([obj class],&count);
    NSMutableString *methodList = [NSMutableString string];
    [methodList appendString:@"[\n"];
    for (int i = 0; i<count; i++) {
        Method method = methods[i];
        SEL sel = method_getName(method);
        [methodList appendFormat:@"%@",NSStringFromSelector(sel)];
        [methodList appendString:@"\n"];
    }

    [methodList appendFormat:@"]"];

    free(methods);

    return methodList;
}
上一篇 下一篇

猜你喜欢

热点阅读