ios-弱引用

在了解弱引用之前,需要先了解散列表的知识

ios-散列表

经常会在oc中使用 __weak typeof(id) weakSelf = self

weakSelf 加入到弱引用表

此时 self 引用计数为 1

weakSelf 引用计数为 2

也就是 加入弱引用表之后,是不影响引用计数的

测试下 weak 引用计数

在这里插入图片描述

实际测试结果 与开始的有出入,差别在于 weakObject 的引用计数为3,不是2

那么久从这个区别开始 探究 弱引用

弱引用表

通过汇编查看__weak 底层调用

在这里插入图片描述

到libobjc 源码中查看

在这里插入图片描述

查看storeWeak(location, newObj)

location 就是weakObjc newObj 为 objc

在这里插入图片描述

根据object 获取散列表的过程,在 ios-散列表 中有介绍,具体细节可以去查看

StripedMap[hash(objc指针)] -> SideTable

SideTable.weak_table -> weak_table_t

在这里插入图片描述

在这里插入图片描述

继续回到 storeWeak 关键逻辑

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

具体弱引用表结构的访问

  • StripedMap[hash(objc指针)] -> SideTable

  • SideTable.weak_table -> (weak_table_t weak_table)

  • weak_table 取出成员 weak_entries数组 (weak_entry_t *weak_entries )

  • 对象地址 通过hash 计算, 得到访问 数组的index

    • hash_pointer(对象地址) & (weak_table->mask), 也就是begin
  • weak_entries[index].referent 也就是 weak_entry_t.referent 可以理解为key,

    用objc与key比较

  • 如果 begin 并未命中

  • index++, index超过边界,取模 从第一个位置又开始,直到与begin相等

  • 如果 遍历的次数超过了 weak_table->max_hash_displacement 上限,返回nil

  • 如果找到 目标entry 也就是entry.referent == objc, 存储 __weakObjc

    • 这里有必要复习下 weak_entry_t 结构

      在这里插入图片描述
      在这里插入图片描述

    • 如果 标识 out_of_line_ness == 2, 则用图中的2结构来存储 __weakObjc

    • 遍历 inline_referrers数组,找到空位 就存储

    • 没找到空位的话,说明 inline_referrers数组已经存满了

    • 这个时候选择使用 图中1结构来存储 __weakObjc 新开辟4个空间出来,把 inline_referrers数组中的内容 拷贝到 referrers中

    • 1结构中的num_refs 设置为4

    • 1结构中的out_of_line_ness 设置标识 REFERRERS_OUT_OF_LINE

    • 1结构中的mask 设置为3 主要是为了索引取模用

    • 1结构中的max_hash_displacement 设置为0

    • 此时 2结构就弃用, 然后继续执行下面的逻辑

    • 向 referrers 插入 __weakObjc 时对 __weakObjc(objc_object**)进行hash,结果 & mask, 得到索引index, 也是begin

    • 如果 referrers[index] 不空, hash_displacement++ , index = ++index & mask, 直到 index == begin 结束

    • 如果hash_displacement > max_hash_displacement, 那么 max_hash_displacement 设置为 hash_displacement

    • referrers[index] = __weakObjc(objc_object**)

    • num_refs++

    • 1结构中 num_refs >= mask + 1, 1结构进行两倍扩容

    • mask 由原来的3 变为了 7,也就是 2*4 - 1

    • 接着执行 上面的

    • 否则 referrers数据备份,创建一个新referrers 进行两倍扩容,备份数据插入 新referrers

    • 新referrers 执行 插入 __weakObjc 逻辑

    • 释放 旧referrers

  • 如果未找到 目标entry 也就是没有发现 一个entry满足 entry.referent == objc,创建新的entry

  • newEntry.referent = objc

  • newEntry.inline_referrers[0] = __weakObjc

  • 对 newEntry.referent 进行hash ,结果 & weak_table->mask 得到目标index

  • weak_table.weak_entries[index] = newEntry

  • weak_table.num_entries++

分析 __weakObj 引用计数为3 非2的问题

StripedMap[hash(objc)].weak_table.weak_entries[hash(objc)].referent

弱引用表中 referent 指向objc 堆内存空间,是不是就导致引用计数 +1 ?

在这里插入图片描述

在这里插入图片描述

先获取局部变量obj,传递给 弱引用表,此时obj引用计数为2

但obj为局部变量,离开作用于,release,引用计数1

此处不需要纠结,应该是跟编译器有关

我们重点放在 弱引用表结构 及存储逻辑上

拓展

callSetWeaklyReferenced

在这里插入图片描述

实现 _setWeaklyReferenced 方法的话,可以做自定义处理

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值