weak属性修饰词解析

1、使用场景

weak常用于修饰代理属性,以防止循环引用导致内存泄漏,__weak与weak基本相同,只不过一个用于修饰变量,主要用于防止block中的循环引用,一个用于修饰属性。

2、weak的原理解析

Runtime在注册某个类时,相应的会维护一个该类的weak表,该weak表实际上是一个hash表,其中

  • key:所指对象的地址
  • value:weak指针的地址数组(注意,这里是一个数组),weak指针地址中的值正是所引用对象的地址

哈希表相对于数组结构来说,查找速度非常快,更重要的是插入或删除某个元素时,数组需要移动大量的元素,而哈希表则不需要,正因为如此,ARC机制下的引用计数表也设计成hash表

  • 不难理解,一个对象可以设置多个weak属性,每新增一个weak属性时,都会在其hash表中对应的value数组中添加一个元素,所以对于一个键值,可以注册多个变量的地址。
  • 当一个对象调用release方法即将销毁时,会调用objc_clear_deallocating函数,此函数会将这个对象的地址作为key去当前对象所属类的hash表中去查找,就能很高效的获取到指向该对象的weak指针的地址数组,随后将获取到的指针数组中的元素全部置为nil,同时删除hash表中对应的key-value键值对。

3、weak实现代码解析

以__weak修饰变量为例

id __weak weakObj = tempObj;

在编译的时候会转化成

id weakObj;
objc_initWeak(&weakObj, tempObj);
objc_destoryWeak(&weakObj);

编译器通过objc_initWeak函数初始化__weak修饰的变量,当变量的作用域结束之后,再通过objc_destoryWeak函数释放该变量。objc_initWeak函数主要是初始化weakObj对象,然后将weakObj引用tempObj对象,代码如下:

weakObj = 0;
objc_storeWeak(&weakObj,tempObj);

objc_destoryWeak函数的操作实际上是:

objc_storeWeak(&weakObj,0);

即让weakObj指针指向的内容为空。

对象的释放步骤:

  1. objc_release
  2. 引用计数为0,执行dealloc方法
  3. _objc_rootDealloc
  4. objc_dispose
  5. objc_destructInstance
  6. objc_clear_deallocating

对象被废弃时,最后调用objc_clear_deallocating,执行的相关操作为:

  1. 从weak表中获取废弃对象的地址为键值的记录
  2. 将包含在记录中的所有附有__weak修饰符变量的地址,赋值为nil
  3. 从weak表中删除该记录
  4. 从引用计数表中删除废弃对象的地址为键值的记录

猜你喜欢

转载自blog.csdn.net/GeekLee609/article/details/82053489