返回

揭秘iOS底层:剖析类加载(上)

IOS

揭秘 iOS 类加载的幕后黑手

引言

探索 iOS 底层的奥秘之旅仍在继续,这一次,我们将深入研究类的加载机制。深入了解类的加载过程,对于 iOS 开发人员来说至关重要,因为它赋予了我们深入了解应用程序行为和提高性能的能力。

Mach-O:类的庇护所

Mach-O 是一种二进制文件格式,用于存储 iOS 应用程序的可执行代码、数据和元数据。类的元数据,例如类名、父类和方法列表,都整齐地存储在 Mach-O 的 __DATA 段中,具体位于 __objc_classlist__objc_catlist 部分。

objc_class:类的蓝图

objc_class 结构体是类的核心数据结构,它包含了类的元数据,如类名、父类、实例变量和方法列表。当类被加载时,Objective-C 运行时会创建相应的 objc_class 实例。

struct objc_class {
  Class isa;
  Class superclass;
  const char *name;
  long version;
  long info;
  long instance_size;
  long ivars;
  const char **ivar_list;
  const char **method_list;
  const char **protocol_list;
  const char **ivars;
  const objc_method_description **methods;
  const objc_property_t **properties;
  const objc_class **protocols;
};

元数据的加载:从 Mach-O 到运行时

当类被加载时,Objective-C 运行时会从 Mach-O 文件中提取元数据,并填充 objc_class 结构体。这个过程主要涉及以下步骤:

  1. 加载 Mach-O 文件: 系统使用 dlopen 加载 Mach-O 文件,并将 Mach-O 的基地址存储在全局变量 _mh_execute_header 中。

  2. 定位 objc_classlist 使用 Mach-O 文件中的 load_commands 表,找到 LC_SEGMENT 命令,然后在段信息中定位 __DATA 段。接着,在 __DATA 段中找到 __objc_classlist 部分的地址。

  3. 遍历 objc_classlist 遍历 __objc_classlist 部分,读取每个 objc_class 结构体的信息,并填充到 Objective-C 运行时的哈希表中。

关联对象的加载:附加的视角

除了元数据,类还可以与关联对象相关联。关联对象是与类或对象关联的附加数据,通常用于存储额外的信息或实现特定功能。Objective-C 运行时通过关联列表(objc_objectlist)管理关联对象。

代码段的加载:方法的舞步

类的代码段(方法实现)存储在 Mach-O 的 __TEXT 段中,具体位于 __text__cstring 部分。当类被调用时,Objective-C 运行时会将代码段加载到内存中,并将其解析为机器指令。

总结:iOS 类加载的蓝图

通过探索 Mach-O 文件结构和 objc_class 结构体,我们揭开了 iOS 类加载的神秘面纱。Objective-C 运行时从 Mach-O 文件中提取元数据,填充 objc_class 结构体,并管理关联对象,从而完成类的加载过程。

深入理解底层机制,对于 iOS 开发人员来说至关重要,它赋予了我们洞察应用程序行为和提高性能的能力。在下篇博客中,我们将继续深入探讨类加载,重点关注方法解析和代码段加载的细节。敬请期待!

常见问题解答

  1. objc_class 结构体包含了哪些信息?

    • objc_class 结构体包含了类的元数据,如类名、父类、实例变量和方法列表。
  2. Objective-C 运行时如何加载元数据?

    • Objective-C 运行时从 Mach-O 文件中提取元数据,并填充 objc_class 结构体。
  3. 关联对象是什么?

    • 关联对象是与类或对象关联的附加数据,通常用于存储额外的信息或实现特定功能。
  4. 代码段存储在哪里?

    • 类的代码段存储在 Mach-O 的 __TEXT 段中。
  5. Objective-C 运行时如何加载代码段?

    • 当类被调用时,Objective-C 运行时会将代码段加载到内存中,并将其解析为机器指令。