编译过程
前段
- 预处理编译阶段:宏的替换,头文件的导入
- 编译阶段:进行词法、语法等的分析和检查,然后生成中间代码IR,产生.i文件
后端
3.生成汇编代码 - 生成目标文件:将汇编文件转文机器码文件,产生.o文件
- 链接:对.0文件中引用其它库的地方进行引用,生成最后的可执行文件(mach-o)
mach-o文件由四部分组成:mach-o头部,load command,section,other data
6.绑定:绑定主要是通过不同的架构,生成对应的mach-o格式可执行文件
静态库
在链接阶段,会将可汇编生成的目标程序与引用的库一起链接打包到可执行文件当中。此时静态库不再变化,本质是拷贝一份到目标程序里。有.a、.lib、.framework等
优势:编译后,目标程序没有外部依赖,自己就可以运行
缺点:由于是拷贝,会导致目标程序体积大,静态库被改变,程序需要重新编译
动态库
程序编译时不会链接到目标程序中,目标程序只存储指向动态库的引用,在运行时才会被载入。比如系统的UIKit,APP的动态库是写入app main bundle根目录中,运行在沙盒中
优势:
- 减少打包之后的app大小
- 共享内存,节约资源,同一份库可以被多个程序使用
- 通过更新动态库,达到更新程序的目的:由于运行时才被载入的特性,可以随时对库进行替换,不许要重新编译代码
缺点:动态载入会带来一部份性能损失,使用动态库需要依赖外部环境,比如版本号等
dyld
dyld(the dynamic link editor) 是苹果的动态链接器,是苹果操作系统的重要组成部分,在app被编译打包成可执行文件格式的mach-o文件后,交给dyld负责连接,加载程序
大致流程如下:
- 设置环境变量
- 加载共享缓存
- 实例化主程序:ImageLoader对象, 这里的image理解为映像
- 加载动态库:加载 DYLD_INSERT_LIBRARIES环境变量 指定的库
- 链接主程序
- 链接动态库
- 执行弱符号绑定
- 执行初始化方法(objc_init):这里会调用map_image(映射镜像) load_images方法,所有的load方法
- 寻找main入口
环境变量配置
在 target -- Edit Scheme -- Run --Arguments -- Environment Variables 配置
DYLD_PRINT_STATISTICS
:设置 DYLD_PRINT_STATISTICS 为YES,控制台就会打印 App 的加载时长,包括整体加载时长和动态库加载时长,即main函数之前的启动时间(查看pre-main耗时),可以通过设置了解其耗时部分,并对其进行启动优化
OBJC_DISABLE_NONPOINTER_ISA
:杜绝生成相应的nonpointer isa(nonpointer isa指针地址 末尾为1 ),生成的都是普通的isa
OBJC_PRINT_LOAD_METHODS
:打印 Class 及 Category 的 + (void)load 方法的调用信息
NSDoubleLocalizedStrings
:项目做国际化本地化(Localized)的时候是一个挺耗时的工作,想要检测国际化翻译好的语言文字UI会变成什么样子,可以指定这个启动项。可以设置 NSDoubleLocalizedStrings 为YES。
NSShowNonLocalizedStrings
:在完成国际化的时候,偶尔会有一些字符串没有做本地化,这时就可以设置NSShowNonLocalizedStrings 为YES,所有没有被本地化的字符串全都会变成大写。
0x8badf00d 通常是用用花费太多时间而无法启动、终止或响应系统事件
0xbad2222 VoIP 应用因为过于频繁重启而被终止
0xdead10cc: 因为在后台运行时占用系统资源
0xdeadfa11强制退出,发生在用户长按开关按钮,出现“滑动关机”,然后长按Home按钮,导致强制退出,app崩溃,大多数是因为应用阻塞了界面