网络上讲解+load函数的文章很多很多,但我总觉得缺少点什么,主要表现在不够系统化,割裂的看待问题。本文只是谈一下个人的理解,主要涉及以下四个方面:
苹果开发文档对+load方法的介绍
dyld是如何加载objc的
objc是如何实现+load方法
+load方法的使用场景及注意事项
写过C语言的同学,一讲到初始化流程,首先想到的是main函数,但在oc里面main却不是第一个执行的函数,别大惊小怪,确实是这样的,且听下面的分解。
初识+load
首先我们来看一下苹果文档是如何介绍+load方法的
Discussion
The load message is sent to classes and categories that are both dynamically loaded and statically linked, but only if the newly loaded class or category implements a method that can respond.
The order of initialization is as follows:
All initializers in any framework you link to.
All +load methods in your image.
All C++ static initializers and C/C++ __attribute__(constructor) functions in your image.
All initializers in frameworks that link to you.
In addition:
A class’s +load method is called after all of its superclasses’ +load methods.
A category +load method is called after the class’s own +load method.
In a custom implementation of load you can therefore safely message other unrelated classes from the same image, but any load methods implemented by those classes may not have run yet.
这段苹果的描述具有很大的信息量,目前大多数文章只谈了in addition里面的内容,本文试图从更宏观的角度来讨论load初始化的过程。
dyld居功至伟
具有Linux下编程经验的同学,启动一个进程,一般都fork出一个新进程,然后再执行exec族函数,加载目标程序并运行。MAC或者iOS系统上执行一个进程,也有着类似的流程,但也有不同,具体可以参看内核XNU的源码。流程如下:
execve //用户双击某个app,用户态调用系统调用execve进入内核态
|--- __mac_execve
|--- exec_activate_image
|--- exec_mach_imgact
|--- load_machfile
|--- parse_machfile //解析Mach-o
|--- load_dylinker // 根据Mach-o中的 LC_LOAD_DYLINKER 来启动dyld
|--- parse_machfile // 解析 dyld ,这个过程中会解析出entry_point
|--- activate_exec_state
|--- thread_setentrypoint // 设置entry_point。
在thread_setentrypoint()函数里面,实际上是把entry_point的地址直接写入到了寄存器里面。
大家看到这里,一定会有两个疑问:
这