共计 2286 个字符,预计需要花费 6 分钟才能阅读完成。
前言
之前咱们聊过了,在 Category 中申明一个属性,能够本人手动实现 set 和 get 办法,然而因为没有成员变量,所以说并不能储值。
咱们能够通过 runtime 的 api 实现让成员变量能够储值,其实实质也并不是贮存,而是通过关联对象实现了这种看似是能够储值的成果。
咱们能够用上面的办法来设置关联对象。
objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key, id _Nullable value, objc_AssociationPolicy policy)
objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key);
明天咱们就来探索一下这种关联对象的实现逻辑。
实现
咱们在 runtime 源码中搜寻objc_setAssociatedObject
,最终能够定位到上面这个办法。
_object_set_associative_reference
通过简略的剖析源码,咱们能够看出关联对象的实现,大抵是由上面四个类联合实现的。
AssociationsManager
AssociationsHashMap
ObjectAssociationMap
ObjcAssociation
简略的抽取和简化一下源码,根本能够得出这四个类的关系。
class AssociationsManager {static AssociationsHashMap * _map}
typedef DenseMap<DisguisedPtr<objc_object>, ObjectAssociationMap> AssociationsHashMap;
typedef DenseMap<const void *, ObjcAssociation> ObjectAssociationMap;
class ObjcAssociation {
uintptr_t _policy;
id _value;
};
大家也能够看一下上面这幅图。
这里很清晰的表明了这几个类的关系,AssociationsManager 有一个 AssociationsHashMap 类型的属性_map,_map 的 key 是 DisguisedPtr<objc_object> 类型,value 是 ObjectAssociationMap 类型,而这个 ObjectAssociationMap 类型中的 key 是一个指针(void*),value 是 ObjcAssociation 类型。这个 ObjcAssociation 中有两个重要的是就是属性,_policy 和_value。
关联对象的设置就是通过这几个类来实现的,下面咱们也剖析完了这几个类的互相关系,那这些类和咱们在调用 objc_setAssociatedObject
时传入的参数关系是怎么样的呢?咱们持续剖析源码。
咱们在看一遍上面这办法。
objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key, id _Nullable value, objc_AssociationPolicy policy)
在调用的时候咱们传入了四个参数,第一个就是咱们的被关联对象,第二个是咱们设置的关联对象的 key,第三个就是咱们要存的值,第四个就是关联的策略(相似 retain,copy 等)
这里先间接说后果吧,其实能够了解为 AssociationsManager 的属性_map 中,以 参数 object为 key,value 是一个 ObjectAssociationMap 类型的 map。ObjectAssociationMap 中,则是以 参数中的 key为 key,value 是一个 ObjcAssociation 类型的对象,最初咱们 参数中的 value 和 policy就贮存在这个 ObjectAssociation 变量中。
好了,这样咱们传的四个参就跟这些类对应上了。就像下图这样子。
留神:
通过源码咱们晓得,AssociationsHashMap 中的 key 并不是应用间接应用了 object,而是一个 DisguisedPtr 类型,然而通过源码咱们能够看到DisguisedPtr<objc_object> disguised{(objc_object *)object};
,说到底这个 key 也是依据咱们的 object 来生成的,所以能够说这个 key 与咱们的 object 是对应关系,从而能够了解为是这个 object 为 key。
不得不说,苹果的设计还是很奇妙的,每一个要设置关联对象的对象对应一个 map,在这个 map 中,应用咱们本人设置的不同的关联对象的 key 为 key,用关联对象的 value 和策略生成一个 ObjcAssociation 类型的对象为 value,而后进行贮存,这样每一个要设置关联对象的对象,具体的每一个关联对象,都能一一对应起来了。
下面的话说的有点拗口,置信大家能够了解。
总结和补充
关联对象并不是贮存在被关联对象自身的,而是贮存在全局的对立的一个 AssociationsHashMap 中。
从源码中咱们还能够看出如果咱们给关联对象设置 nil,则代表移除该关联对象。
同时还要留神,因为咱们的 object 其实是一个对象,这就要波及内存治理问题,当咱们的这个 object 开释后,其实整个 AssociationsHashMap 中其对应项都会被移除,这个当前咱们探讨内存治理的时候再说。
objc_getAssociatedObject 实现咱们就不具体分析了,如果看动了 set 的实现,get 其实很容易了解。
感激浏览。