• iOS weak底层实现原理


    今年年底做了很多决定,离开工作三年的深圳,来到了上海,发现深圳和上海在苹果这方面还是差距有点大的,上海的市场8成使用swift编程,而深圳8成的使用OC,这点还是比较让准备来上海打拼的苹果工程师有点小压力的。毕竟以后苹果还是swift使用的多,现在已经swift4.x了,所以早点接触,还是有优势的,不过。咱们闲话少说,今天我们将继续讲述OC修饰属性的一个Weak修饰符的底层实现,有时间我会花时间讲述swift4.x。

    一、weak基本用法

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

    拓展:为什么修饰代理使用weak而不是用assign?

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

    二、weak原理概括

    weak表其实是一个哈希表,key是所指对象的指针,value是weak指针的地址数组。(value是数组的原因是:因为一个对象可能被多个弱引用指针指向)

    Runtime维护了一张weak表,用来存储某个对象的所有的weak指针。

    weak原理实现过程三步骤

    1. 初始化开始时,会调用objc_initWeak函数,初始化新的weak指针指向对象的地址

      2.紧接着,objc_initWeak函数里面会调用objc_storeWeak() 函数,objc_storeWeak() 函数的作用是用来更新指针的指向,创建弱引用表。

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

    拓展:详细步骤

    1. 初始化开始时,会调用objc_initWeak函数,初始化新的weak指针指向对象的地址

    当我们初始化weak变量时,runtime会调用NSObject.mm中的objc_initWeak,而objc_initWeak函数里面的实现如下:

    id objc_initWeak(id *location, id newObj) {
    // 查看对象实例是否有效,无效对象直接导致指针释放
        if (!newObj) {
            *location = nil;
            return nil;
        }
        // 这里传递了三个 bool 数值
        // 使用 template 进行常量参数传递是为了优化性能
        return storeWeakfalse/*old*/, true/*new*/, true/*crash*/>
        (location, (objc_object*)newObj);
    }

    通过上面代码可以看出,objc_initWeak()函数首先判断指针指向的类对象是否有效,无效,直接返回;否则通过storeWeak()被注册为一个指向value的_weak对象

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

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

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

    1、调用objc_release
    2、因为对象的引用计数为0,所以执行dealloc
    3、在dealloc中,调用了_objc_rootDealloc函数
    4、在_objc_rootDealloc中,调用了object_dispose函数
    5、调用objc_destructInstance
    6、最后调用objc_clear_deallocating,详细过程如下:
       a. 从weak表中获取废弃对象的地址为键值的记录
       b. 将包含在记录中的所有附有 weak修饰符变量的地址,赋值为   nil
       c. 将weak表中该记录删除
       d. 从引用计数表中删除废弃对象的地址为键值的记录

    本文讲述了weak底层实现原理,也是面试经常被问到的一点,希望对大家有所帮助,谢谢!

  • 相关阅读:
    centOS学习part6:安装oracle 11g
    centOS学习part5:oracle 11g安装之环境准备
    centOS学习part4:安装配置vsftp
    centOS学习part3:远程工具VNC的安装与配置
    centOS学习part2:安装JDK及tomcat
    centOS学习part1:操作系统安装
    SSH开发实践part4:Spring整合Struts
    SSH开发实践part3:hibernate继承映射
    读《实战GUI自动化测试》之:第三步,如何提高测试结果分析的效率
    读《实战 GUI 产品的自动化测试》之:第二步,构建利于维护的自动化测试系统
  • 原文地址:https://www.cnblogs.com/guohai-stronger/p/10161870.html
Copyright © 2020-2023  润新知