有一个工程DyldDemo依赖A和B两个动态库,依赖信息如下图所示:

DyldDemo关键内容
AppDelegate.m:
+ (void)load {
NSLog(@"AppDelegate load");
}
ViewController.m:
+ (void)load {
NSLog(@"ViewController load");
}
ViewController+Additions.m:
+ (void)load {
NSLog(@"ViewController Additions load");
}
AppDelegate+Additions.m:
#import "AppDelegate+Additions.h"
__attribute__((constructor)) void func3() {
printf("\n ---func3--- \n");
}
__attribute__((constructor)) void func4() {
printf("\n ---func4--- \n");
}
@implementation AppDelegate (Additions)
+ (void)load {
NSLog(@"AppDelegate Additions load");
}
@end
main.m:
__attribute__((constructor)) void func1() {
printf("\n ---func1--- \n");
}
__attribute__((constructor)) void func2() {
printf("\n ---func2--- \n");
}
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
NSLog(@"---MAIN---");
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
appDelegateClassName = NSStringFromClass([AppDelegate class]);
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
A 关键内容
Compile Sources:

A1.m:
#import "A1.h"
__attribute__((constructor)) void func_A1() {
printf("\n ---func_A1--- \n");
}
@implementation A1
+ (void)load {
NSLog(@"A1 Load");
}
@end
A2.m:
#import "A2.h"
__attribute__((constructor)) void func_A2() {
printf("\n ---func_A2--- \n");
}
@implementation A2
+ (void)load {
NSLog(@"A2 Load");
}
@end
A1+Addtions.m:
#import "A1+Addtions.h"
@implementation A1 (Addtions)
+ (void)load {
NSLog(@"A1 Addtions Load");
}
@end
B 关键内容
Compile Sources:

B1.m:
#import "B1.h"
__attribute__((constructor)) void func_B1() {
printf("\n ---func_B1--- \n");
}
@implementation B1
+ (void)load {
NSLog(@"B1 Load");
}
@end
B2.m:
#import "B2.h"
__attribute__((constructor)) void func_B2() {
printf("\n ---func_B2--- \n");
}
@implementation B2
+ (void)load {
NSLog(@"B2 Load");
}
@end
问题:程序运行到[ViewController viewDidLoad]控制台输出什么?
⚠️在Debug环境下,不考虑编译器优化。并且没有进行二进制重排。
问题分析:
- 首先初始化
B,再初始化A,最后初始化主程序DyldDemo。
-
B分析
由于B1.m在B2.m前面,所以先执行B1的+ load方法。所以B1的输出为:
B1 Load
B2 Load
---func_B1---
---func_B2---
-
A分析
A中的文件顺序A1+Additions、A2、A1。所以A中的输出应该为:
A2 Load
A1 Load
A1 Addtions Load
---func_A2---
---func_A1---
-
DyldDemo分析
文件顺序为main.m、AppDelegate+Additions、ViewController+Additions、ViewController、AppDelegate。根据A和B的分析同理可得DyldDemo的输出为:
ViewController load
AppDelegate load
AppDelegate Additions load
ViewController Additions load
---func1---
---func2---
---func3---
---func4---
---MAIN---
- 所以整体输出为
B1 Load
B2 Load
---func_B1---
---func_B2---
A2 Load
A1 Load
A1 Addtions Load
---func_A2---
---func_A1---
ViewController load
AppDelegate load
AppDelegate Additions load
ViewController Additions load
---func1---
---func2---
---func3---
---func4---
---MAIN---
运行代码验证:

总结
-
Dyld初始化image是按Link Binary With Libraries顺序逐个初始化的,从下标1开始,最后再初始化主程序(下标0)。可以理解为是按image进行分组的。 -
image内部是先加载所有类的+ load,再加载分类的+ load,最后加载C++全局构造函数。(类load->分类load->C++构造函数)。+load是objc中调用的,C++全局构造函数是在dyld中调用的。(在不考虑二进制重排等的优化下,image内部的顺序默认是按Compile Sources中顺序进行的)。 -
main函数是在dyld返回入口函数(main)之后才调用的。










