# 23.Swift项目编译速度优化

## 前言

本文将从代码层面探究如何分析并优化 `Swift` 代码的编译速度。

## 一、 检查代码中的编译瓶颈

### 1.1 项目配置

通过警告的形式标识出超出设定值的代码，下面以设置 `100ms` 为界限为例

在 `BuildSettings` 中 `other swift flags` 下添加下面的配置：

![1](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2F7f9a801123af1ada27bd41b01dd73250b12ee4bd.png?generation=1631018503527763\&alt=media)

* -Xfrontend -warn-long-function-bodies=100
* -Xfrontend -warn-long-expression-type-checking=100

> 仅在 `DEBUG` 下添加就行了，毕竟只是用来检测

### 1.2 编译检查

`Clean` 后编译一次，这里就可以看到很多的警告了：

![2](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2F50a6e5f15f35d83ee21eeed9e90ad68e2854b182.png?generation=1631018498616840\&alt=media)

![3](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2Ff9474d83d3b66a70571f6875f0e28091e07b7ab2.png?generation=1631018507349635\&alt=media)

你可能觉得这样检测有点不方便，毕竟项目的警告可能有几百上千个。下面介绍一个工具：`BuildTimeAnalyzer-for-Xcode`

## 二、 BuildTimeAnalyzer-for-Xcode 使用说明

首先 Clone 项目代码（或者直接[下载代码](https://github.com/RyukieSama/BuildTimeAnalyzer-for-Xcode)）

```
git clone https://github.com/RyukieSama/BuildTimeAnalyzer-for-Xcode.git
```

### 2.1 项目配置

在 `BuildSettings` 中 `other swift flags` 下添加下面的配置：

* -Xfrontend -debug-time-function-bodies

然后 `Clean` 项目，重新 `Build`。

### 2.2 打开 BuildTimeAnalyzer.xcodeproj

这里有三种方式来使用

#### a. 直接运行

![直接运行](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2Fdae7e87f15d1b8cab5033cfd2b947fb68d677cbc.png?generation=1631018507583212\&alt=media)

#### b. 导出App

`Product - Archive`

![导出App](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2Fdca2e8a1032d48f791c2d3b554f536807f981799.png?generation=1631018508220244\&alt=media)

导出一个App文件，以后即可直接使用了。

![App](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2F66144a9fe32e55baabd6acfc003342f4fbec0e9d.png?generation=1631018504836343\&alt=media)

#### c. 懒人方式-下载即用

这里我搞好了一个包，直接可用。支持 `Intel`， `Apple Silicon`。

[下载：BuildTimeAnalyzer.zip即可](https://github.com/RyukieSama/BuildTimeAnalyzer-for-Xcode)

### 2.3 查看编译耗时日志

![04](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2F1f31550870262a87b6cb2276d5708daac34f533c.png?generation=1631018509540479\&alt=media)

在列表中点击刚才自己的配置完成并编译后的项目，即可查看日志。

![05](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2Fb7f35a2889478941f33d37034de5eddf67f6174b.png?generation=1631018506959608\&alt=media)

显示了整体编译耗时，还标有具体代码的行数与函数名，点击可跳转。

> 每次时间不一定一样，根据电脑运行情况会有一些变化，但是整体的瓶颈趋势还是基本一致的

## 三、 优化项目

这里个人建议结合上面两种方式来定位。

* `BuildTimeAnalyzer` 用来找到瓶颈更加直观
* 第一个直接添加警告的方式用来定位具体代码更准确

### 3.1 项目配置

为了结合两种方式，这里我的配置如下：

![09](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2Fdfa1093ece0a1d5b9dc51be319c2286beec16fdb.png?generation=1631018508821706\&alt=media)

***`BuildTimeAnalyzer`\*\*\*\* \*\*\*\*分析结果***

![我的电脑配置](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2F1df20dbac8a0e0535d51878909cc618e0115e747.png?generation=1631018500539754\&alt=media)

![12](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2F454f9b130a2b8fb37b22ac7c10225b9439269cbc.png?generation=1631018506793401\&alt=media)

* 最高： `DataBaseDataCenter+Overview` 耗时 `35075ms`

### 案例1：较长的逻辑

![10](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2Fef25db864cc11049ab967835d29c1731e9283003.png?generation=1631018505676306\&alt=media)

这里是使用 `WCDB` 瓶颈显示的是连续的调用 `WCDB` 中的范型函数来获得一个 `condition` 进行数据库操作。

![11](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2Fbecc40e147ebab2929d53dddd6e19517688db6e4.png?generation=1631018508627562\&alt=media)

#### 优化：拆分

![14](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2Ffc6d2cbf27dce96736fe7e02a9ea80664a2078d8.png?generation=1631018507905179\&alt=media)

Clean 后再 Build，查看是否有效：

![15](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2F95dd90cd5adb0b1288609c27d3bdbd904ebb4102.png?generation=1631018502616352\&alt=media)

`DataBaseDataCenter+Overview` 耗时由 `35075ms` 下降至 `19007ms`，减少了近一半的时间。那么再把 `DataBaseDataCenter+Overview` 其他相同场景的代码也优化一下看看结果吧。

![16](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2F0b7eda4e604fd99728578340b3c238997eb2a660.png?generation=1631018508552480\&alt=media)

优化了另一处一样的场景后，时间降到了 `915ms`。

### 案例2：字符串拼接

这里使用了 `+` 进行字符串的拼接

![19](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2F9ade803094117180199371ce13055ae0ed12f99e.png?generation=1631018509103700\&alt=media)

![17](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2Fbc53ea2cc9da88cb2028da9c118fe552d1dbe357.png?generation=1631018507284953\&alt=media)

此处总耗时 `2596ms`。

#### 优化：使用 "xx\\(xx)xx" 拼接

使用 `\(preString)~\(endString)` 的方式进行拼接

![20](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2F44b2ab35d5824a995b0350dd1f8aa86f60ba0822.png?generation=1631018509167591\&alt=media)

![18](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2Fc34dc8c8cf58bd2eecffe16f40c59e40c831bc63.png?generation=1631018506754855\&alt=media)

效果明显，降到了 `617ms`。

### 案例3：少用 ??

![22](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2Ffc6482e286ad503539b91858efc097a868e559a3.png?generation=1631018501918997\&alt=media)

![21](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2F3867363d7da2b49884f220e64b3c0466116559ab.png?generation=1631018499698195\&alt=media)

此处用了较多的 `??`。整体耗时 `3561ms`。

#### 优化：提前 gurad/if let 解包或者减少调用 ?? 次数

![23](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2F8457cc3b00c6b00b374e275425db6d74a312a392.png?generation=1631018509319782\&alt=media)

![24](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2F44531fbd972254619c6c36664c1d50a5ca4417fc.png?generation=1631018507826596\&alt=media)

整体降到了 `855ms`。

## 四、 总结

此处列举了一些我在项目中的一些成功优化的点，当然还有一些没有找到合适优化方式的点。再有一些有价值的点结局的话我会再来更新进文中。而且这里是以个人项目作为小白鼠进行的优化，企业项目中一般可优化的地方就更多了。而且我们也不能为了优化而优化，不能影响了源代码的可读性与连贯性。

也欢迎大家交流补充

## 参考

* [BuildTimeAnalyzer中文手册](https://github.com/RyukieSama/BuildTimeAnalyzer-for-Xcode)
* [配置说明](https://github.com/apple/swift/commit/18c75928639acf0ccf0e1fb6729eea75bc09cbd5)
* [iOS 微信编译速度优化分享](https://mp.weixin.qq.com/s/-wgBhE11xEXDS7Hqgq3FjA)
* [Optimizing Swift build times](https://github.com/RyukieSama/Optimizing-Swift-Build-Times)
