三、weak 探究

作者: 流小贝 | 来源:发表于2022-05-05 08:39 被阅读0次

    1、weak基本介绍:

        weak是弱引用,用weak来修饰、描述所引用对象的计数器并不会加1,而且weak会在引用对象被释放的时候自动置为nil,这也就避免了野指针访问坏内存而引起奔溃的情况,另外weak也可以解决循环引用。

    2、weak原理概括:

       2.1、基本原理

            weak表其实是一个哈希表,key是所指对象的指针,value是weak指针的地址数组。(value是数组的原因是:因为一个对象可能被多个弱引用指针指向)。同时Runtime维护了一张weak表,用来存储某个对象的所有的weak指针。

      2.2、weak原理实现过程三步骤

            1)第一步初始化,初始化会先调用objc_initWeak函数,初始化新的weak指针指向对象的地址,当我们初始化weak变量时,runtime会调用NSObject.mm中的objc_initWeak

            2)第二步objc_initWeak函数里面会调用objc_storeWeak()函数,objc_storeWeak()函数的作用是用来更新指针的指向,创建弱引用表

            3)第三步调用clearDeallocating函数,而clearDeallocating函数首先根据对象的地址获取weak指针地址的数组,然后紧接着遍历这个数组,将其中的数组开始置为nil,把这个entry从weak表中删除,最后一步清理对象的记录。

    3、当weak指向的对象被释放时,如何让weak指针置为nil的呢?

        3.1、调用objc_release

        3.2、因为对象的引用计数为0,所以执行dealloc

        3.3、在dealloc中,调用了_objc_rootDealloc函数

         3.4、在_objc_rootDealloc中,调用了object_dispose函数

         3.5、调用objc_destructInstance

         3.6、最后调用objc_clear_deallocating,详细过程如下:

            (1)从weak表中获取废弃对象的地址为键值的记录

            (2)将包含在记录中的所有附有weak修饰符变量的地址,赋值为nil

            (3)将weak表中该记录删除

            (4)从引用计数表中删除废弃对象的地址为键值的记录

    4、问题提问

      4.1、为什么修饰代理使用weak而不是用assign或strong?

         首先用strong修饰会引起循环引用,那句self.delegate = self;,这个就是普通的循环引用问题。

          至于assign,首先大家都知道assign修饰的是基础数据分布在栈区,系统自动管理内存不进行引用计数,而代理delegate指向的对象是存储在堆区,离开作用域即便delegate指向的对象(非oc对象)销毁了,delegate中依然会保存之前对象的地址,所以使用之后如果没有置为nil,可能会产生野指针。解决办法是weak修饰之后自动置为nil,就不会产生野指针。

           综上所述:ARC与MRC下有什么不同?就是MRC下只能用assign修饰,而在ARC下既能用weak也能用assign,只是用assign要做多一定工作

    4.2、assign可用来修饰基本数据类型,也可修饰OC的对象,为什么不用assin修饰对象

           如果用assign修饰对象类型指向的是一个强指针,当指向的这个指针释放之后,它仍指向这块内存,必须要手动给置为nil,否则会产生野指针,如果还通过此指针操作那块内存,会导致EXC_BAD_ACCESS错误,调用了已经被释放的内存空间;而weak只能用来修饰OC对象,而且相比assign比较安全,如果指向的对象消失了,那么它会自动置为nil,不会导致野指针。

    相关文章

      网友评论

        本文标题:三、weak 探究

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