通过运行时的关联对象我们可以为分类添加“成员变量”,但是这里所实现的效果只是看上去是给类添加了成员变量,并非真实的,因为在运行期,对象的内存布局已经确定,如果添加实例变量就会破坏类的内部布局,这对编译型语言来说是灾难性的。那这个“成员变量”到底被添加到哪里去了呢?
关于这个问题,我们可以通过查看源码得到答案
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存储。 - 所有对象的关联内容都在同一个全局容器中。