ios-关联对象

1,444 阅读2分钟

关联对象常见的一种做法

在分类里想增加属性,由于只会生成 set get方法,并不会存在 属性与成员

这个时候的做法往往是 在set 里 调用objc_setAssociatedObject

get里使用 objc_getAssociatedObject

那么 关联对象究竟如何实现,这是本次探究的主题

找源码

image.png

image.png

出现了两个关键变量

image.png

关于 DisguisedPtr<objc_object> ,可以对比另一篇博客 ios-弱引用 里提到的结构,顺便了解一下 它是怎么用的

image.png

ObjcAssociation 里 value的访问类似于 我们常规的property retain copy的修饰

又出现了两个变量

image.png

AssociationsManager

image.png image.png image.png

可能你会没什么感觉,太抽象的代码,没关系,你也可以忽略,因为 全局变量 不是靠我们程序员初始化的,libc 会在c++初始化器运行之前就调用了

只需要知道 AssociationsManager get() 可以获取到全局的 AssociationsHashMap

AssociationsHashMap结构

image.png

为了对 AssociationsHashMap 结构更有感知,直接通过它的使用是最好的方式

image.png

image.png

image.png

查找的过程是这样

hash(objc伪装地址) --> 得出 index,也就是buckets起始位置偏移索引index

buckets 首地址 + index --> 得到bucket

bucket->getFirst() ---- key

bucket->getSecond() ---- Value

首次 通过 hash 得到 bucket,比较 bucket->getFirst() 与 disguisedPointer (也就是伪装地址) 是否相等

如果不匹配,则顺序挨个遍历查找

调试 AssociationsHashMap

image.png

image.png

image.png

image.png

image.png

image.png

再看AssociationsHashMap 结构

  • Buckets

  • NumEntries

  • NumTombstones

  • NumBuckets ------- 数量为4 后续会存在扩容逻辑

从这层开始,第一步 就是 根据 hash(objc) 找 Buckets 的哪一个, 第一次可能命中 bucket,也可能没找到,也可能冲突,总之没找到,就去遍历查找

关联对象表 - 直观结构

image.png

假设对象 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}