KVO的本质

1、KVO也就是key-value-observing(键值观察),利用一个key来找到某个属性并监听其值得改变;
1.1、KVO的使用非常简单,调用实例对象的addObserver:forKeyPath:options:context:方法;
1.2、对象在相关属性发生值变化时,会调用观察者的observerValueForKeyPath:ofObject:change:context方法;
2、为什么同一个类创建出来的对象,KVO的对象在修改属性时会多调用一个观察方法?
2.1、从对象本质我们了解到,成员属性或成员方法内存中保存在类对象中,所有实例方法都一样;
2.2、既然同一个类下的实例对象调用同一个方法执行了不同的动作,很有可能这两个实例对象的类对象不一样;
2.3、通过运行时机制中的object_getClass()方法可以验证类对象名为NSKVONotifying_xxxx;
2.4、然而使用实例对象的class方法得到的并不是这个值
3、获取当前类对象的方法实现
3.1、相关代码

1
2
3
4
5
6
7
8
9
10
11
- (void)methods
{
    unsigned int count;
    Method *methods = class_copyMethodList(object_getClass(self), &count);
    NSMutableArray *methodArray = [NSMutableArray array];
    for (int i = 0; i < count; i++) {
        SEL sel = method_getName(methods[i]);
        [methodArray addObject:NSStringFromSelector(sel)];
    }
    NSLog(@"%@", methodArray);
}

3.2、调用有KVO对象的methods方法可以得到他重写了属性的set方法、class方法、dealloc方法;
3.3、通过superclass可以验证NSKVONotifying_xxxx是原有类对象的子类;
3.4、调用实例对象的methodForSelector:方法可以验证KVO对象set方法的实现为_NSSetFloatValueAndNotify()函数;
3.5、_NSSetFloatValueAndNotify()函数中实现分别调用:
willChangeValueForKey:
set方法
didChangeValueForKey:
其中didChangeValueForKey:方法中调用了监听方法,可重写类中的该三个方法,打印验证;
4、总结:
4.1、参考:Objective-C中对象的分类与本质(isa&superclass)
4.2、KVO的本质是在运行时修改原实例对象的isa指针,使其指向一个新的类对象,该类对象是原类对象的子类;
4.2、类对象中重写了观察属性的set方法、class方法、dealloc方法;
4.3、类对象中set方法的实现实质上为Foundation中的_NSSetFloatValueAndNotify()函数;
4.4、类对象中重写的set方法不仅实现了set方法本身,还调用了观察方法达到监听的目的;
4.5、可通过runtime中的object_getClass()、class_getSuperclass()及isa、superclass属性等验证相关结论;
4.6、还可重写willChangeValueForKey:、didChangeValueForKey:等方法来验证调用顺序;
4.7、可以lldb调试中使用thread backtrack命令查看set方法调用的前后方法验证;

Leave a Reply