iOS进阶:编译速度优化

编译耗时的检查

  1. Swift的表达式和函数的编译时长检查

    build settingOther Swift Flags中设置:

    1
    2
    3
    4
    // 编译耗时超过 100ms 的函数或表达式给出警告
    -Xfrontend -warn-long-function-bodies=100

    -Xfrontend -warn-long-expression-type-checking=100
  2. 查看总耗时

    在终端执行如下命令,重启Xcode,编译后可以看到总耗时:

    1
    defaults write com.apple.dt.Xcode ShowBuildOperationDuration -bool YES

编译优化怎么做

针对OC的优化——重点在于减少无效的引用

  1. pch文件:删除使用不多的引用
  2. .h文件:减少.h文件中的引用,将.h中导入改为声明#import改为@class

针对Swift的优化——重点在于减少类型检查

  • 明确变量类型

  • 闭包:

    • 避免闭包的嵌套——因为swift推断闭包方法需要把内部所有代码都推断完才能推断出闭包的类型
    • 避免使用闭包来初始化属性
  • lazy变量:减少lazy变量的使用,或将lazy变量声明改为函数调用形式

    不推荐写法:

    1
    2
    3
    4
    5
    6
    private(set) lazy var chartViewColors: [UIColor] = [
    UIColor.red,
    UIColor.blue,
    UIColor.green,
    UIColor.purple,
    ]

    推荐写法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    private(set) lazy var chartViewColors: [UIColor] = createChartViewColors()

    private func createChartViewColors() -> [UIColor] {
    return [
    UIColor.red,
    UIColor.blue,
    UIColor.green,
    UIColor.purple,
    ]
    }
  • 集合类型:明确集合类型,避免使用 + 合并两个集合

  • 三元运算符——?::使用if...else...代替

  • nil的聚合运算——??:使用条件绑定来解决

  • 一行表达式不要做太多事情,比如既做判断又做计算

其他

  • 项目设置:使用New Xcode Build System
  • DSYM:将 Debug Information Format 改为 DWARF,设置在Debug下不生成DSYM,只在Release下生成
  • 模块化:将pod第三方库打包成.a文件,减少编译时间;缺点是不方便调试

编译器层面优化

WMO(Whole-Module Optimization)简介

WMO即全模块优化。在编译项目时,会将同属于一个 Module(可以理解为一个 Target、一个 Package)的所有源代码都串起来,进行整体的一个分析与优化,区别于 Single-File Optimization(单文件优化,简称 SFO)。WMO 可以更好的统筹全局,去 inline 函数调用、排除死函数(即写了却从不调用的函数)等等,使编译速度加快。但是,WMO 只是在 Release 模式下成为了默认且推荐的选项,在 Debug 模式下默认依然是 None。

怎样利用WMO优化编译速度

Uber 的开发团队偶然发现如果把所有 Model 文件全部合并到一个文件去编译, 那编译时间会从 1min 35s 减少到 17s, 那么我们如果把所有代码文件都合并到一起, 那就可以极大地优化编译速度了。

WHO(Whole-Module-Optimization) 也会把文件合并起来再进行编译, 实际使用时我们发现编译虽然快了, 但对于编译时间的减少还是远没有直接把文件合并到一起那么有效。

主要原因是因为 WMO 除了合并文件之外, 还会在预编译阶段做一些优化,来方便编译器将方法的调用优化为静态调用或者内联进去:

  • 检测没有被调用的方法和类型, 在预编译期去掉它们;
  • 给没有被继承的类, 没有被继承的方法加上 final 标签。

这些优化会对于程序的效率有很大的提升, 但编译时间会有所增加。

最终发现,通过增加一个编译宏就可以做到只合并文件, 而不做优化:

设置 -> Build Setting -> Add User-Defined Settings, 设置key 为 SWIFT_WHOLE_MODULE_OPTIMIZATION, value 设为 YES, 然后把优化级别设为 None,这样就可以实现Debug模式下的编译耗时的优化。