直捣黄龙一探weak实现原理

作者: WallisW | 来源:发表于2019-03-31 19:22 被阅读119次

开门见山先抛砖

我们知道,weak是修饰属性的一个关键字。一般用于解决循环引用的问题,它的特殊之处在于:被修饰对象遭到销毁后,weak指针会自动置为nil。也正是这个特性让它代替了之前的unsafe_unretained关键字。

那么,它咋就这么聪明呢?凭什么就可以自动置为你了呢?

这也是iOS面试经常遇到的一个问题,我大概百度了下。答案大多是这样一个思路:

runtime层维护了一个weak指针和引用对象映射的哈希表,当引用对象引用计数为零时,系统会查找这个表找到它对应的weak指针并置为nil。

一般,我们面试这么答。基本也就过关了,那么本着做学问一丝不苟的精神:真的是这样吗?或者只是这样吗?

拨云见日之引玉

首先,毫无疑问weak底层的实现依赖于runtime。那么解决方法就来了:

Talk is cheap.Show you the code.

这里使用的是obj4-750源码,打开项目文件,观察Source源文件很容易找到objc-weak.mm便是与weak相关的源文件。

objc-weak.mm

代码里定义的基本的使用方法,我们结合注释找到注册并绑定weak指针与引用对象的代码。

新增weak绑定

我们发现函数参数"weak_table_t",看上去就好像是我们上面说到的维护weak与引用对象的表(table)。

那么,欲知真相如何,请随超哥移步结构体内部一窥究竟。

weak_table_t weak_entry_t

对于weak_table_t,内部有一个weak_entry_t类型的数组,num_entries表示当前weak_table_t维护的对应关系数量(应该是和weak_entries.count相同)。

我们再去看weak_entry_t的结构,根据超哥的注释不难发现,这个结构才是负责维护weak指针与引用对象对应关系的"幕后黑手"。

综上两个weak底层实现依赖的核心数据结构是数组,那么接下来就看看它是怎么实现自动置nil的。

weak置nil实现

简单明了,一看就懂,原来如此!有些底层的原理,上网百度听别人说一百遍,不如老老实实自己看代码一遍。看完了,既能使自己理解得更深刻,还能装13…何乐而不为呢?

欲听下回分解

所以准确地说底层对weak的维护依赖的是是一个数组结构,那么开头我们说的那个答案它究竟对吗???

某种意义上讲,它也是对的。只是说得不够透彻,虽不能说是一针见血,毕竟也是见了点红色的影子。其实,从上面的源码截图,我们也能得知它是对的。

weak_table_t

有没有发现,这里的注释说weak_table_t是一个全局的表。引用对象作为key,指向它的多个entry结构作为value。

说到这,weak_table_t上层依赖的也是一个全局的哈希表???。我们根据???找到了weak_table_t结构。这个???表整体是负责对象的生命周期管理(引用计数管理和weak指针管理)。

预知???逸闻,且等超哥下回分解!

--20190331傍晚



暗夜之手

即使明天早上,
枪口和血淋淋的太阳,
让我交出自由、青春和笔,
我也绝不会交出这个夜晚!
-----------------------------诗人 北岛

相关文章

网友评论

    本文标题:直捣黄龙一探weak实现原理

    本文链接:https://www.haomeiwen.com/subject/tmmhpxtx.html