oc中 关于weak的粗浅理解
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了oc中 关于weak的粗浅理解相关的知识,希望对你有一定的参考价值。
参考技术A 这两天在研究oc中的weak实现原理,只是看明白了一点浅显的东西,参考地址:
https://www.jianshu.com/p/2c2da28a5a53
以下是自己的理解:
基本用法:
如果是面试,面试官肯定会要深入的问,为什么对象释放的时候,指针会自动置为 nil ,如何实现的?
系统维护了一个全局的map表。这个表里有多个 sideTable ,sideTable里面有 weak_table (弱引用表)
当通过 __weak 让一个指针指向一个对象的时候,如果这个对象之前没有被注册,就会调用 objc_initWeak() 方法
如果是已经注册的,会调用 objc_storeWeak() 。对象销毁的时候,会调用 objc_destroyWeak()
当然, objc_initWeak() 和 objc_destroyWeak() 最终都会调用 objc_storeWeak() 。
objc_storeWeak() 这个方法里,先根据对象的地址,从全局map表中找到对应的 sideTable ,然后再从 sideTable 中找到对应的 weak_table ,找到弱引用表后,生成或者更新 weak_entry_t 。 weak_entry_t 里面存了对象的地址和指向对象的所有弱引用指针。
对象销毁的时候,是找到对应的 weak_entry_t ,把里面的指针都移除掉
OC中weak的原理
参考技术A weak是OC中用于打破对象间的循环引用的一种技术。
1. weak 修饰一个变量时,表示该指针变量可以使用但不拥有该对象;及 weak 引用指向对象时,对象的引用计数并不增加。
当 weak 引用一个对象时,Runtime会将引用的信息( key 为指向对象的指针, value 是 weak 指针的变量的地址数组)封装到 weak_entry_t 结构体中,具体存储到 DisguisedPtr 类中。
OC的Runtime会维护一个 weak 表( weak_table_t 结构体),用于维护指向对象的所有 weak 指针,是 weak_entry_t 的结构体上的一层封装。
weak_table_t 类型的结构体,是一个哈希表,但是在这个表中的操作并不是线程安全的。
于是Runtime对于 weak_table_t 上又进行了一层封装,也就是 SideTable 。 SideTable 这层封装对于 weak 引用机制的主要目的是解决线程安全的问题。
weak_entry_t 是 weak_table_t 具体存储的数据类型
DisguisedPtr<T> 是Runtime对于普通对象指针(引用)的一个封装,目的在于隐藏 weak_table_t 的内部指针。
RefcountMap 用于OC的引用计数机制; slock 实际上是 os_unfair_lock_s 类型,用于处理线程安全的问题; weak_table 弱引用表,用于存储对象的弱引用的数组。 SideTable 提供的方法都与锁有关。
strong :该对象强引用delegate,引用计数+1,外界不能销毁 delegate 对象,会导致循环引用( Retain Cycles )
weak :指明该对象并不持有delegate这个对象,delegate的销毁由外部控制。当 delegate 指向的对象销毁后,自动 delegate = nil 。
assign :具有 weak 的效果,但需要手动设置 nil 。
为什么用 weak 不用 assign ?
assign 是指针赋值,不操作引用计数, delegate 用完后如果没有设置为 nil ,有可能产生野指针;而 weak 指向的 delegate 一旦用完,自动就 nil 了,不会产生野指针。
assign :一般修饰值类型的属性;
strong :修饰引用类型的属性,内存计数+1;
weak :修饰引用类型的属性,原理见上述讲解;但是 weak 修饰的属性虽然不持有,在释放对象时会查询和释放其对应的弱引用表,这样是会增加内存和性能上的开销。
OC Runtime之Weak(3)
OC Runtime之Weak(2)
OC Runtime之Weak(1)
以上是关于oc中 关于weak的粗浅理解的主要内容,如果未能解决你的问题,请参考以下文章