有一个工程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
。
根据
image.pngdyld
源码可知dyld
初始化image list
从下标1
开始,最后再初始化主程序(下标0
)。而image list
顺序与Link Binary With Libraries
顺序有关。
dyld
相关源码如下:
image.png
-
B
分析
由于B1.m
在B2.m
前面,所以先执行B1
的+ load
方法。所以B1
的输出为:
B1 Load
B2 Load
---func_B1---
---func_B2---
根据
image.pngdyld
的源码可知c++
的全局构造函数调用在+load
方法之后。
dyld
相关源码(ImageLoader::recursiveInitialization
):
-
A
分析
A
中的文件顺序A1+Additions
、A2
、A1
。所以A
中的输出应该为:
A2 Load
A1 Load
A1 Addtions Load
---func_A2---
---func_A1---
根据
image.pngdyld
和objc
源码可知,分类的+load
方法加载是在所有类的+load
方法加载后,c++
构造函数前调用的。
objc-loadmethod.mm
:
-
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---
+load
是在objc
中调用的,c++
全局构造函数是在dyld
中调用的,这两个调用都在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---
运行代码验证:
image.png总结
-
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
)之后才调用的。
网友评论