研究KVO的时候我们发现系统使用Objective-C 强大的runtime功能实现了这个功能。属性类class中并没有实现KVO通知的相关方案,而是在调用addObserver之后定义属性类的子类subclass,subclass里边实现了属性的setter方法,setter方法中实现发动通知的功能。然后subclass中实现class函数,还让返回属性类的class,再让属性类对象的isa指向subclass,这样就伪装成表面上看还是属性类自己实现的通知功能。通过原理我们可以看出, 必须使用属性方法或者setValue:forKey方法赋值才会发送通知,直接赋值是不会收到通知的。
实际上系统定了一个叫做 NSKVONotifying_ClassTest的子类,子类中实现了
setY: , setX: , class , dealloc , _isKVOA函数,这个 _isKVOA函数应该是个私有函数,用来判断是否kvo框架生成的类, x, y, xy对象的运行时类都指向NSKVONotifying_ClassTest,通过class函数返回的类还是指向ClassTest,但是control对象的不管运行时类还是class函数返回的类都指向 ClassTest。这样就验证了系统是通过定义Classtest类的子类来实现属性方法发送通知的,系统很聪明,子类中并没有实现setZ方法,因为我们并没有对属性z添加观察者。
Objective-C 之 isa
每个
Objective
-
C
对象有个指向其具体类的指针
isa
。但
Objective-C
是一
种运行时动态特性很强的语言。换句话说,
Objective-C
的运行时动态特性决
定了某个对象在生命周期内,其所属的类是可能改变的,也就是
isa
指针有可
能改变,
Apple
把这种技术叫做
IsA-swizzling
。举个例子,当对某个对象使
用了
KVO
之后,
Objective-C
实际上是动态的创建了一个该对象所属类的子
类,并把该对象的所属类指向这个子类。这时候该对象的
isa
指针就很不幸的
被改变了。实际上,
isa
指针是
Objective-C
运行时系统使用到的一个变量
,我们在程序中应该尽量不要依赖它。