iOS 底层原理 02:OC 对象初始化之内存探索之旅
2024-02-11 17:53:48
前言
iOS 开发中,我们经常会遇到 OC 对象初始化的问题,例如 objc 无法编译、调试问题等。这些问题往往让人摸不着头脑,但如果你能深入理解 OC 对象初始化的底层原理,就能轻松解决这些问题。
OC 对象初始化
OC 对象初始化是一个复杂的过程,涉及到内存分配、对象布局、方法调用等多个方面。为了深入理解这一过程,我们需要从 OC 对象的内存布局开始讲起。
OC 对象的内存布局
OC 对象的内存布局如下图所示:
+----------------------------------+
| isa |
+----------------------------------+
| 成员变量 1 |
+----------------------------------+
| 成员变量 2 |
+----------------------------------+
| ... |
+----------------------------------+
| 成员变量 n |
+----------------------------------+
| 方法表 (Method Table) |
+----------------------------------+
其中:
- isa 指针:指向对象的类对象,它是一个指向 Class 结构体的指针。
- 成员变量:对象的成员变量,包括实例变量和属性。
- 方法表:存储着对象的所有方法的地址。
OC 对象的初始化过程
OC 对象的初始化过程分为两个阶段:
- 内存分配:首先,系统会为对象分配一块内存空间。这块内存空间的大小由对象的 instanceSize 决定。instanceSize 是一个宏,它计算出对象的所有成员变量和方法表占用的总空间大小。
- 对象布局:内存分配完成后,系统会对对象进行布局,即把对象的成员变量和方法表放入正确的位置。
OC 对象初始化的底层实现
OC 对象的初始化过程是由 objc_alloc 和 objc_init 两个函数实现的。objc_alloc 函数负责分配内存空间,而 objc_init 函数负责对对象进行布局。
objc_alloc 函数
objc_alloc 函数的原型如下:
id objc_alloc(Class cls);
其中:
- cls:要分配内存的对象的类对象。
objc_alloc 函数首先会调用 class_getInstanceSize 函数计算出对象所需的内存空间大小,然后调用 malloc 函数分配这块内存空间。
objc_init 函数
objc_init 函数的原型如下:
id objc_init(id obj);
其中:
- obj:要初始化的对象。
objc_init 函数首先会把对象的 isa 指针指向正确的类对象,然后调用对象的 init 方法对对象进行初始化。
为何 8 + 8 + 4 -> 32,而不是 24?
在 OC 对象的内存布局中,我们看到 instanceSize 的计算公式是 8 + 8 + 4。很多人可能会疑惑,为什么是 32,而不是 24?
这是因为 OC 对象的内存布局是按照 8 字节对齐的。也就是说,每个对象的内存地址必须是 8 的倍数。而 8 + 8 + 4 正好是 20,不满足 8 字节对齐的要求。因此,系统会自动在对象后面补齐 4 个字节,使对象的总大小变成 32 字节。
结语
通过本文,我们深入探索了 OC 对象初始化的底层原理,从内存分配到对象布局,再到 objc_alloc 和 objc_init 函数的实现,相信大家对 OC 对象初始化有了更深入的理解。希望这些知识能帮助大家解决在 OC 开发中遇到的各种问题。