> For the complete documentation index, see [llms.txt](https://ryukiedev.gitbook.io/wiki/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ryukiedev.gitbook.io/wiki/ios/you-hua/07.app-qi-dong-su-du-you-hua.md).

# 07.App启动速度优化

### 一：启动时间

> 启动时间 = main()之前的时间 + main()之后的时间

#### 1.1 如何衡量时间

* 通过添加环境变量可以打印出APP的启动时间分析
  * `Edit scheme` -> `Run` -> `Arguments`
  * `DYLD_PRINT_STATISTICS` 设置为 `1`
  * 如果需要更详细的信息，那就将 `DYLD_PRINT_STATISTICS_DETAILS` 设置为 `1`

#### 1.2 作为开发者我们可以介入的地方有哪些？

![Image](/files/-MVqY0N6bXxyTQFNaicv)

### 二: main()之前

#### 2.1 dyld

`iOS`的动态链接器，可以用来装载`Mach-O`文件（可执行文件、动态库等）

* 启动APP时，`dyld`所做的事情有
  * 装载APP的可执行文件，同时会递归加载所有依赖的动态库
  * 当`dyld`把可执行文件、动态库都装载完毕后，会通知`Runtime`进行下一步的处理

#### 2.2 runtime

* 启动APP时，`runtime`所做的事情有
  * 调用`map_images`进行可执行文件(`.o`)内容的解析和处理
  * 在`load_images`中调用`call_load_methods`，调用所有`Class`和`Category`的`+load`方法
  * 进行各种`objc`结构的初始化（注册`Objc类` 、`初始化类对象`等等）
  * 调用`C++静态初始化器`和`__attribute__((constructor))`修饰的函数

到此为止，可执行文件和动态库中所有的符号(`Class`，`Protocol`，`Selector`，`IMP`，…)都已经按格式成功加载到内存中，被`runtime`所管理

#### 2.3 可优化点

* 减少不必要的`framework`
* `framework`应当设为`optional`和`required`，如果该`framework`在当前App支持的所有iOS系统版本都存在，那么就设为`required`，否则就设为`optional`，因为`optional`会有些额外的检查
* 合并或者删减一些OC类，关于清理项目中没用到的类，使用工具AppCode代码检查功能，查到当前项目中没有用到的类如
* 删除废弃方法
* `+load`里少做事情，用`+initialize`方法和`dispatch_once`取代所有的`__attribute__((constructor))`、`C++静态构造器`、`ObjC`的`+load`
* 尽量不用C++虚函数(创建虚函数有开销)
* `Swift`尽量使用`Struct`

### 三: main()之后

> 主要是App本身相关的一些初始化服务

* 不适用xib/sb,使用代码加载首页视图
* NSUserDefaults实际上是在Library文件夹下会生产一个plist文件，如果文件太大的话一次能读取到内存中可能很耗时，这个影响需要评估，如果耗时很大的话需要拆分(需考虑老版本覆盖安装兼容问题)
* 每次用NSLog方式打印会隐式的创建一个Calendar，因此需要删减启动时各业务方打的log，或者仅仅针对内测版输出log
* 梳理应用启动时发送的所有网络请求，是否可以统一在异步线程请求
* 首页相关控制器的`viewDidLoad`/`viewWillAppear`里少做操作或者延迟做
* 少做/不做 I/O 操作,或者异步做

### 参考

> <https://techblog.toutiao.com/2017/01/17/iosspeed/>
