β

【iOS】weak的底层实现

Harries Blog™ 9 阅读

weak底层千千万,吾竟装作看不见…

【iOS】weak的底层实现

weak基本用法

weak是弱引用,用weak描述修饰或者所引用对象的计数器不会加一,并且会在引用的对象被释放的时候自动被设置为nil,大大避免了野指针访问坏内存引起崩溃的情况,另外weak还可以用于解决循环引用。

weak原理概括

weak表其实是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址数组。weak的底层实现的原理是什么?

Runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash表,Key是所指对象的地址, value 是weak指针的地址(这个地址的值是所指对象指针的地址)数组。

为什么value是数组?因为一个对象可能被多个弱引用指针指向

weak原理实现步骤

weak 的实现原理可概括三步:

1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。

【iOS】weak的底层实现

初始化流程图

2、添加引用时:objc_initWeak函数会调用 objc_storeWeak() 函数, objc_storeWeak() 的作用是更新指针指向,创建对应的弱引用表。

【iOS】weak的底层实现

更新指针,创建弱引用表

3、释放时,调用clearDeallo cat ing函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后 遍历 这个数组把其中的 数据 设为nil,最后把这个entry从weak表中 删除 ,最后清理对象的记录。

weak实现三步骤详细过程:

1、初始化时:runtime会调用objc_initWeak函数,objc_initWeak函数会初始化一个新的weak指针指向对象的地址。

示例 代码

 NSObject *obj = [[NSObject alloc] init];
 id __weak obj1 = obj;

当我们初始化一个weak变量时,runtime会调用 NSObject.mm 中的objc_initWeak函数。

这个函数在Clang中的声明如下:

id objc_initWeak(id *object, id value);

而对于 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);
}

这里先判断了其指针指向的类对象是否有效,无效直接释放返回,不再往深层调用函数。否则,object将通过bjc_storeWeak函数被注册为一个指向value的__weak对象。

注意:objc_initWeak函数有一个前提条件:就是object必须是一个没有被注册为__weak对象的有效指针。而value则可以是null,或者指向一个有效的对象。

2、添加引用时:objc_initWeak函数会调用 objc_storeWeak() 函数, objc_storeWeak() 的作用是更新指针指向,创建对应的弱引用表。

objc_storeWeak的函数声明如下:

id objc_storeWeak(id *location, id value);

objc_storeWeak() 的具体实现,请参考 weak弱引用实现的方式 ,这里的实现很复杂,没看懂,没看懂。

3、释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。

当weak引用指向的对象被释放时,又是如何去处理weak指针的呢?当释放对象时,其基本流程如下:

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

拓展补充

weak,__unsafe_unretained, unowned 与 assign区别

致谢

参考 博客

weak 弱引用的实现方式

iOS 底层解析weak的实现原理(包含weak对象的初始化,引用,释放的分析)

个人简书地址

PS:如果您想和业内技术大牛交流的话,请加qq群(527933790)或者关注微信公众 号(AskHarries),谢谢!

转载请注明原文出处: Harries Blog™ » 【iOS】weak的底层实现

作者:Harries Blog™
追心中的海,逐世界的梦
原文地址:【iOS】weak的底层实现, 感谢原作者分享。

发表评论