通过运行时的关联对象我们可以为分类添加“成员变量”,但是这里所实现的效果只是看上去是给类添加了成员变量,并非真实的,因为在运行期,对象的内存布局已经确定,如果添加实例变量就会破坏类的内部布局,这对编译型语言来说是灾难性的。那这个“成员变量”到底被添加到哪里去了呢?
关于这个问题,我们可以通过查看源码得到答案
1 | void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) { |
结论:
AssociationsManager
是顶级的对象,维护了一个 AssociationsHashMap
哈希表的单例键值对映射;
AssociationsHashMap
是一个无序的哈希表,维护了从对象地址到 ObjectAssociationMap
的映射;
ObjectAssociationMap
是一个 C++ 中的 map ,维护了从 key
到 ObjcAssociation
的映射,即关联记录;
ObjcAssociation
是一个 C++ 的类,表示一个具体的关联结构,主要包括两个实例变量,_policy
表示关联策略,_value
表示关联对象。
每一个对象地址对应一个 ObjectAssociationMap
对象,而一个 ObjectAssociationMap
对象保存着这个对象的若干个关联记录。
关系图如下:
关联对象的本质
- 关联对象由
AssociationsManager
管理并在AssociationsHashMap
存储。 - 所有对象的关联内容都在同一个全局容器中。