返回

iOS 底层原理 02:OC 对象初始化之内存探索之旅

IOS

前言

iOS 开发中,我们经常会遇到 OC 对象初始化的问题,例如 objc 无法编译、调试问题等。这些问题往往让人摸不着头脑,但如果你能深入理解 OC 对象初始化的底层原理,就能轻松解决这些问题。

OC 对象初始化

OC 对象初始化是一个复杂的过程,涉及到内存分配、对象布局、方法调用等多个方面。为了深入理解这一过程,我们需要从 OC 对象的内存布局开始讲起。

OC 对象的内存布局

OC 对象的内存布局如下图所示:

+----------------------------------+
| isa                           |
+----------------------------------+
| 成员变量 1                    |
+----------------------------------+
| 成员变量 2                    |
+----------------------------------+
| ...                            |
+----------------------------------+
| 成员变量 n                    |
+----------------------------------+
| 方法表 (Method Table)       |
+----------------------------------+

其中:

  • isa 指针:指向对象的类对象,它是一个指向 Class 结构体的指针。
  • 成员变量:对象的成员变量,包括实例变量和属性。
  • 方法表:存储着对象的所有方法的地址。

OC 对象的初始化过程

OC 对象的初始化过程分为两个阶段:

  1. 内存分配:首先,系统会为对象分配一块内存空间。这块内存空间的大小由对象的 instanceSize 决定。instanceSize 是一个宏,它计算出对象的所有成员变量和方法表占用的总空间大小。
  2. 对象布局:内存分配完成后,系统会对对象进行布局,即把对象的成员变量和方法表放入正确的位置。

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 开发中遇到的各种问题。