dyld(the dynamic link editor):苹果动态链接编译器。
研究在iOS中动态库的加载顺序是什么样子:
1.实验篇
(1)没有依赖关系:
制作dylibA、dylibB、dylibC三个动态库(不了解动态库制作的问度娘),且3个动态库间没有依赖关系,同时在每个库中添加一个Class,暂且以Class的load方法的调用顺序当做是动态库的加载顺序,比如dylibA:
@implementation ClassA
+ (void)load {
NSLog(@"dylibA loaded");
}
@end
将三个库加到demo项目工程中,并且保证Build Phases-Link Binary With Libraries中的顺序:dylibA > dylibB > dylibC,运行结果:
Demo[53199:17384949] dylibA loaded
Demo[53199:17384949] dylibB loaded
Demo[53199:17384949] dylibC loaded
调整下Link Binary With Libraries中的顺序:dylibC > dylibB > dylibA,运行结果:
Demo[53265:17397552] dylibC loaded
Demo[53265:17397552] dylibB loaded
Demo[53265:17397552] dylibA loaded
通过实验知道:在没有依赖关系的情况下,动态库的加载顺序由Link Binary With Libraries中的拖入顺序决定,可以通过Link Binary With Libraries来控制动态库的加载顺序。
(2)单一依赖关系
dylibA依赖dylibB,dylibB依赖dylibC,简单改造三个库,如在dylibB中import下dylibC的头文件,dylibA中同理:
#import "ClassB.h"
#import <dylibC/dylibC.h>
@implementation ClassB
+ (void)load {
NSLog(@"dylibB loaded");
}
@end
Link Binary With Libraries中顺序:dylibA > dylibB > dylibC运行结果:
Demo[53570:17450857] dylibC loaded
Demo[53570:17450857] dylibB loaded
Demo[53570:17450857] dylibA loaded
发现三个库的加载顺序是反的,修改顺序:dylibC > dylibA > dylibB,运行结果不变。结果可知:动态库的加载顺序还受依赖关系影响,被依赖的子节点优先加载。
(3)组合依赖关系
dylibA、dylibB、dylibC没有依赖关系,dylibA嵌入式依赖了dylibD、dylibE(dylibF)
Demo[97898:19286936] dylibD loaded
Demo[97898:19286936] dylibF loaded
Demo[97898:19286936] dylibE loaded
Demo[97898:19286936] dylibA loaded
Demo[97898:19286936] dylibB loaded
Demo[97898:19286936] dylibC loaded
通过修改dylibA-Link Binary With Libraries中dylibD、dylibE的顺序调整为:
Demo[97982:19305235] dylibF loaded
Demo[97982:19305235] dylibE loaded
Demo[97982:19305235] dylibD loaded
Demo[97982:19305235] dylibA loaded
Demo[97982:19305235] dylibB loaded
Demo[97982:19305235] dylibC loaded
总结动态库的加载顺序为:先根据拖入配置的链接顺序加载,如有依赖的先递归式加载依赖。
2.源码篇
通过几个实验对动态库的加载顺序有个大概的理解,下面我们通过源码进一步了解动态库的加载机制(dyld源码/本文使用版本:dyld-635.2)。
为了便于分析过程,我们在上面demo中的位于子节点的dylibF库的load方法添加一个符号断点,获取下这个load方法的调用栈:
#0 +[ClassF load]
#1 load_images ()
#2 dyld::notifySingle(dyld_image_states, ImageLoader const*, ImageLoader::InitializerTimingList*) ()
#3 ImageLoader::recursiveInitializatio