iOS 独门武功秘籍之奥义:OC 对象原理剖析(上)——alloc、init、new 全解析
2023-12-03 17:18:23
春节之夜,辗转难眠,我翻开《秘籍·最新 objc4-818.2 源码》时,不由得陷入了沉思。夜深人静,我步入了第一个符号断点 libSystem_initializer,顺着堆栈信息,我来到了赫赫有名的 dyld,随后又经历了一系列流程,才最终抵达了 libSystem 的舞台。至此,我正式开启了探索 iOS 独门武功秘籍——Objective-C 对象原理的征程。
第一重秘籍:alloc & init
alloc:内存分配的序曲
alloc,是 Objective-C 对象创建的开篇之作。它负责为即将诞生的对象预留一块专属的内存空间,为其登场亮相做好准备。alloc 的调用过程如下:
Class cls = [SomeClass class];
id obj = [cls alloc];
当我们调用 [cls alloc] 时,它会向系统请求一块足以容纳 SomeClass 实例的内存空间,并返回指向该内存空间的指针,即 obj。这块内存空间就是 SomeClass 对象的家园,它将在这里安身立命,发挥作用。
init:对象的初始化之舞
alloc 为对象分配了内存空间后,便轮到 init 登场了。init 的使命是将这块空旷的内存空间装点一新,为对象赋予生命。init 的调用过程与 alloc 类似:
Class cls = [SomeClass class];
id obj = [[cls alloc] init];
当我们调用 [[cls alloc] init] 时,它会首先调用 alloc 为 SomeClass 对象分配内存空间,然后调用 init 方法对这块内存空间进行初始化,使之成为一个合法的 SomeClass 对象。
ARC 与非 ARC 下的 alloc & init
在 Automatic Reference Counting(ARC)的怀抱中,alloc 和 init 的行为会略有不同。ARC 是一种自动内存管理机制,它会自动跟踪对象的创建和销毁,并自动释放不再使用的对象的内存。在 ARC 下,alloc 和 init 的调用方式与非 ARC 下相同,但 ARC 会在幕后默默地为我们管理对象的内存。
而在 Non-Automatic Reference Counting(非 ARC)的江湖中,alloc 和 init 就需要我们亲自动手管理对象的内存了。在非 ARC 下,我们需要手动调用 release 来释放不再使用的对象的内存。
第二重秘籍:new
new 是 Objective-C 中另一个创建对象的方法。与 alloc 和 init 相比,new 的行为更为直接。new 的调用过程如下:
SomeClass *obj = [[SomeClass alloc] init];
SomeClass *obj = [SomeClass new];
当我们调用 [SomeClass new] 时,它会首先调用 alloc 为 SomeClass 对象分配内存空间,然后自动调用 init 方法对这块内存空间进行初始化,使之成为一个合法的 SomeClass 对象。
new 与 alloc & init 的主要区别在于,new 会自动调用 init 方法,而 alloc & init 需要我们手动调用 init 方法。在 ARC 下,alloc & init 和 new 的行为是完全相同的。但是在非 ARC 下,alloc & init 和 new 的行为却截然不同。对于非 ARC,alloc & init 需要我们手动管理内存,而 new 会自动为我们管理内存。
第三重秘籍:从底层探索 alloc、init 和 new
要真正掌握 alloc、init 和 new 的奥秘,我们必须深入到底层去探索它们的实现细节。alloc、init 和 new 都是由编译器生成的,我们可以通过查看编译器生成的汇编代码来了解它们的底层实现。
alloc 的底层实现
_objc_allocate:
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
cmpq $0, -8(%rbp)
je .L12
movabsq $-1, %rax
jmp .L13
.L12:
movabsq $0, %rax
.L13:
popq %rbp
retq
init 的底层实现
_objc_init:
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
movq %rsi, -16(%rbp)
movq -16(%rbp), %rdi
callq _objc_msgSendSuper2
popq %rbp
retq
new 的底层实现
_objc_new:
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
movq %rax, -16(%rbp)
movq -16(%rbp), %rdi
callq _objc_msgSendSuper2
popq %rbp
retq
通过查看编译器生成的汇编代码,我们可以看到 alloc、init 和 new 的底层实现都非常简单。alloc 只负责分配内存空间,init 负责初始化对象,new 则将 alloc 和 init 合二为一,自动完成内存分配和对象初始化。
结语
alloc、init 和 new 是 Objective-C 中创建对象的三个基本方法。alloc 负责为对象分配内存空间,init 负责初始化对象,new 将 alloc 和 init 合二为一。在 ARC 下,alloc & init 和 new 的行为完全相同。但是在非 ARC 下,alloc & init 需要我们手动管理内存,而 new 会自动为我们管理内存。通过深入探索 alloc、init 和 new 的底层实现,我们可以更加深入地理解它们的奥秘。