关联对象常见的一种做法
在分类里想增加属性,由于只会生成 set get方法,并不会存在 属性与成员
这个时候的做法往往是 在set 里 调用objc_setAssociatedObject
get里使用 objc_getAssociatedObject
那么 关联对象究竟如何实现,这是本次探究的主题
找源码
出现了两个关键变量
关于 DisguisedPtr<objc_object> ,可以对比另一篇博客 ios-弱引用 里提到的结构,顺便了解一下 它是怎么用的
ObjcAssociation 里 value的访问类似于 我们常规的property retain copy的修饰
又出现了两个变量
AssociationsManager
image.png
image.png
image.png
可能你会没什么感觉,太抽象的代码,没关系,你也可以忽略,因为 全局变量 不是靠我们程序员初始化的,libc 会在c++初始化器运行之前就调用了
只需要知道 AssociationsManager get() 可以获取到全局的 AssociationsHashMap
AssociationsHashMap结构
为了对 AssociationsHashMap 结构更有感知,直接通过它的使用是最好的方式
查找的过程是这样
hash(objc伪装地址) --> 得出 index,也就是buckets起始位置偏移索引index
buckets 首地址 + index --> 得到bucket
bucket->getFirst() ---- key
bucket->getSecond() ---- Value
首次 通过 hash 得到 bucket,比较 bucket->getFirst() 与 disguisedPointer (也就是伪装地址) 是否相等
如果不匹配,则顺序挨个遍历查找
调试 AssociationsHashMap
再看AssociationsHashMap 结构
Buckets
NumEntries
NumTombstones
NumBuckets ------- 数量为4 后续会存在扩容逻辑
从这层开始,第一步 就是 根据 hash(objc) 找 Buckets 的哪一个, 第一次可能命中 bucket,也可能没找到,也可能冲突,总之没找到,就去遍历查找
直观结构
假设对象 objc, 属性 key 属性值 value
- objc 求hash ==> index
- buckets[index] ==> bucket
- bucket->second ==> sub_buckets (bucke->first ==> objc)
- key 求hash ==> sub_index
- sub_buckets[sub_index] ==> sub_bucket
- sub_bucket->second ==> association. (sub_bucket->first ==> key)
- association ==> {policy, value}