iOS经典面试题之“runtime是如何实现weak变量的自动置nil”

一、weak 属性特点
  • weak 表明该属性定义了一种“非拥有关系” (nonowning relationship);
  • 为 weak 属性设置新值时,设置方法既不保留新值,也不释放旧值;
  • 同 assign 类似,然而在属性所指的对象释放时候,属性值也会清空(nil out)。
二、runtime 如何实现 weak 属性
① 实现步骤
  • 初始化时:runtime 会调用 objc_initWeak 函数,初始化一个新的 weak 指针指向对象的地址。
  • 添加引用时:objc_initWeak 函数会调用 objc_storeWeak(&weakPo, Model) 函数。
  • 释放时:调用 clearDeallocating 函数,clearDeallocating 函数首先根据对象地址获取所有 weak 指针地址的数组,然后遍历这个数组把其中的数据设为 nil,最后把这个 entry 从 weak 表中删除,最后清理对象的记录。
② objc_storeWeak(&weakPo, Model) 作用
  • objc_storeWeak(&weakPo, Model) 的作用是更新指针指向(指针可能原来指向着其他对象,这时候需要将该 weak 指针与旧对象解除绑定,会调用到 weak_unregister_no_lock),如果指针指向的新对象非空,则创建对应的弱引用表,将 weak 指针与新对象进行绑定(即把赋值对象(Model)的内存地址作为键值key,将weak修饰的属性变量(weakPo)的内存地址(& weakPo)作为value),会调用到weak_register_no_lock,注册到 weak 表中。在这个过程中,为了防止多线程中竞争冲突,会有一些锁的操作。
  • 如果Model 为0(nil),那么把变量 weakPo 的内存地址 &weakPo 从 weak 表中删除,可以把 objc_storeWeak(&weakPo, Model) 理解为:objc_storeWeak(value, key),并且当key变nil,将value置nil。
  • 在 Model 非 nil 时,weakPo 和 Model 指向同一个内存地址,在 Model 变 nil 时,weakPo 变 nil。此时向 weakPo 发送消息不会崩溃:在 Objective-C 中向 nil 发送消息是安全的。
三、runtime 是如何实现 weak 变量的自动置 nil ?
  • runtime 对注册的类,会进行内存布局,从一个粗粒度的概念上来讲,这时候 weak 对象会放入一个 hash 表中,这是一个全局表,表中是用 weak 指向的对象内存地址作为 key,用所有指向该对象的 weak 指针表作为 value。
  • 当此对象的引用计数为 0 的时候会 dealloc,假如该对象内存地址是 address,那么就会以 address 为 key,在这个weak 表中搜索,找到所有以 address 为键的 weak 对象,从而设置为 nil。
  • 简而言之,对象释放的时候 - dealloc: 步骤如下:
    • C++函数释放: object_ cxxDestruct;
    • 移除关联属性:_ object_ remove_ assocations;
    • 将弱引用自动设置nil : weak_ clear_ no_ lock(&table.weak_ table, (id)this);
    • 引用计数处理: table.refcnts.erase(this);
    • 销毁对象: free(obj);
四、底层调用流程

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Forever_wj/article/details/115034919