序言:各个社区有关 Objective-C weak 机制的实现分析文章有很多,然而 Swift 发布这么长时间以来,有关 ABI 的分析文章一直非常少,似乎也是很多 iOS 开发者未涉及的领域… 本文就从源码层面分析一下 Swift 是如何实现 weak 机制的。
准备工作
由于 Swift 源码量较大,强烈建议大家把 repo clone 下来,结合源码一起来看这篇文章。
$ git clone https://github.com/apple/swift.git
Swift 整个工程采用了 CMake 作为构建工具,如果你想用 Xcode 来打开的话需要先安装 LLVM,然后用 cmake -G
生成 Xcode 项目。
我们这里只是进行源码分析,我就直接用 Visual Studio Code 配合 C/C++ 插件了,同样支持符号跳转、查找引用。另外提醒一下大家,Swift stdlib 里 C++ 代码的类型层次比较复杂,不使用 IDE 辅助阅读起来会相当费劲。
正文
下面我们就正式进入源码分析阶段,首先我们来看一下 Swift 中的对象(class
实例)它的内存布局是怎样的。
HeapObject
我们知道 Objective-C 在 runtime 中通过 objc_object
来表示一个对象,这些类型定义了对象在内存中头部的结构。同样的,在 Swift 中也有类似的结构,那就是 HeapObject
,我们来看一下它的定义:
struct HeapObject {
/// This is always a valid pointer to a metadata object.
HeapMetadata const *metadata;
SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS;
HeapObject() = default;
// Initialize a HeapObject header as appropriate for a newly-allocated object.
constexpr HeapObject(HeapMetadata const *newMetadata)
: metadata(newMetadata)
, refCounts(InlineRefCounts::Initialized)
{
}
// Initialize a HeapObject header for an immortal object
constexpr HeapObject(HeapMetadata const *newMetadata,
InlineRefCounts::Immortal_t immortal)
: metadata(newMetadata)
, refCounts(InlineRefCounts::Immortal)
{
}
};
可以看到,HeapObject
的第一个字段是一个 HeapMetadata
对象,这个对象有着与 isa_t
类似的作用,就是用来描述对象类型的(等价于 type(of:)
取得的结果),只不过 Swift 在很多情况下并不会用到它,比如静态方法派发等等。
接下来是 SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS
,这是一个宏定义,展开后即:
RefCounts<InlineRefCountBits> refCounts;
这是一个相当重要东西,引用计数、弱引用、unowned 引用都与它有关,同时它也是 Swift 对象(文中后续的 Swift 对象均指引用类型,即 class
的实例)中较为复杂的一个结构。
其实说复杂也并不是很复杂,我们知道 Objective-C runtime 里就有很多 union 结构的应用,例如 isa_t
有 pointer 类型也有 nonpointer 类型,它们都占用了相同的内存空间,这样做的好处就是能更高效地使用内存,尤其是这些大量使用到的东西,可以大大减少运行期的开销。类似的技术在 JVM 里也有,就如对象头的 mark word。当然&#