KVO的本质
以p1对象为例 p1对象的isa指针在经过KVO监听之后已经指向了NSKVONotifyin_Person类对象,
- NSKVONotifyin_Person其实是Person的子类,其superclass指针是指向Person类对象
- NSKVONotifyin_Person是runtime在运行时生成的。
- p1对象在调用setage方法的时候,会根据p1的isa找到NSKVONotifyin_Person,在NSKVONotifyin_Person中找setage的方法及实现。
NSKVONotifyin_Person中的setage方法中其实调用了 Fundation框架中C语言函数 _NSsetIntValueAndNotify,_NSsetIntValueAndNotify内部做的操作相当于,
- 首先调用willChangeValueForKey 将要改变方法,
- 之后调用父类的setage方法对成员变量赋值,
- 最后调用didChangeValueForKey已经改变方法。
- didChangeValueForKey中会调用监听器的监听方法,最终来到监听者的observeValueForKeyPath方法中。
- 事实上foundtion内部还有其他函数比如:
_NSSetBoolValueAndNotify、_NSSetCharValueAndNotify、_NSSetFloatValueAndNotify、_NSSetLongValueAndNotify等等函数
窥探NSKVONotifyin_Person类的内部
重写class方法是为了隐藏NSKVONotifyin_Person apple不希望将NSKVONotifyin_Person类暴露出来,并且不希望我们知道NSKVONotifyin_Person内部实现,所以在内部重写了class类,直接返回Person类
iOS用什么方式实现对一个对象的KVO?(KVO的本质是什么?)
答. 当一个对象使用了KVO监听,iOS系统会修改这个对象的isa指针,改为指向一个全新的通过Runtime动态创建的子类,子类拥有自己的set方法实现,set方法实现内部会顺序调用willChangeValueForKey方法、原来的setter方法实现、didChangeValueForKey方法,而didChangeValueForKey方法内部又会调用监听器的observeValueForKeyPath:ofObject:change:context:监听方法。
**如何手动触发KVO **
答. 被监听的属性的值被修改时,就会自动触发KVO。如果想要手动触发KVO,则需要我们自己调用willChangeValueForKey和didChangeValueForKey方法即可在不改变属性值的情况下手动触发KVO,并且这两个方法缺一不可。
关联对象实现原理
-(void)setName:(NSString *)name {
objc_setAssociatedObject(self, @"name",name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSString *)name {
return objc_getAssociatedObject(self, @"name");
}
参数一:id object : 给哪个对象添加属性,这里要给自己添加属性,用self。
参数二:void * == id key : 属性名,根据key获取关联对象的属性的值,在**objc_getAssociatedObject**中通过次key获得属性的值并返回。
参数三:** id value** : 关联的值,也就是set方法传入的值给属性去保存。
参数四:objc_AssociationPolicy policy : 策略,属性以什么形式保存。 有以下几种
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
OBJC_ASSOCIATION_ASSIGN = 0, // 指定一个弱引用相关联的对象
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, // 指定相关对象的强引用,非原子性
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, // 指定相关的对象被复制,非原子性
OBJC_ASSOCIATION_RETAIN = 01401, // 指定相关对象的强引用,原子性
OBJC_ASSOCIATION_COPY = 01403 // 指定相关的对象被复制,原子性
};
- 移除所有关联对象
- (void)removeAssociatedObjects {
// 移除所有关联对象
objc_removeAssociatedObjects(self);
}
实现关联对象技术的核心对象有
- AssociationsManager
- AssociationsHashMap
- ObjectAssociationMap
- ObjcAssociation
其中Map同我们平时使用的字典类似。通过key-value一一对应存值。
通过上图我们可以总结为:一个实例对象就对应一个ObjectAssociationMap,而AssociationsHashMap中存储着多个实例对象的ObjectAssociationMap,ObjectAssociationMap存储着多个次实例对象关联对象的key以及ObjcAssociation,ObjcAssociation中存储着关联对象的value和policy策略。
由此我们可以知道关联对象并不是放在了原来的对象里面,而是自己维护了一个全局的map用来存放每一个对象及其对应关联属性表格。
通过上图我们可以总结为:一个实例对象就对应一个ObjectAssociationMap,而ObjectAssociationMap中存储着多个此实例对象的关联对象的key以及ObjcAssociation,为ObjcAssociation中存储着关联对象的value和policy策略。
由此我们可以知道关联对象并不是放在了原来的对象里面,而是自己维护了一个全局的map用来存放每一个对象及其对应关联属性表格。