优化 iOS 项目编译时间

8,264 阅读4分钟

随着项目越来越大,编译时长也会越来越长。那么编译的优化就必不可少了。

查看编译时长

在 xcode 的编译 log 可以查看时长,也可以查看总时长,每一个 文件的编译时长。

swift 类型检查耗时

对于 swift 来说,编译耗时的主要就是类型检查 在 xcode => build settings => Other Swift Flags 添加下面设置,可以看到 swift 的表达式和函数的 类型检查的时长。并给出警告。

-Xfrontend -warn-long-function-bodies=100 (100 means 100ms here, you should experiment with this value depending on your computer speed and project)

-Xfrontend -warn-long-expression-type-checking=100

后面的 100 单位是毫秒,超过这个值,就会给出警告。

查看总耗时

在终端执行:

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

重启 xcode,编译可以看到总耗时

项目设置优化

使用 New Xcode Build System

dSYM

可以设置在 debug 不生成 dSYM,只在 release 生成。

模块化

可以把 pod 等第三方库先打包成 .a 文件,然后再放入项目里面,这样 pod 的第三方库就编译时间就会减少。但是这样一来 调试就不方便了,所以这是个取舍问题。

Object-C 的优化

oc 的优化,重点在于减少无效引用,对编译时长的优化提升非常明显。 通过 log 看哪些文件编译时间比较长的文件,进行优化。

快捷键⌘ + 8

优化pch文件

1、检查 pch 文件,删除用的不多的引用。

h 文件

.h 文件尽量少写引用。引用尽量写在 .m文件里。可以在编译 log 中看有哪些文件编译时间比较长的,大部分都可以通过 优化引用来解决。

删除不用引用

项目时间长了之后,因为功能变化,有些类可能已经不用了,但是引用还在,这个一定要删掉。

经过优化,编译时长减少了2-3 分钟。

Swift 优化

优化选择

根据之前说法,把 swift 的文件合并成一个,可以大大减少编译时长。但是 xcode10 已经没用这个选项了。 xcode10 已经给出了优化的选择,我们主要选择正确的选项就可以,根据自己的需求,一般 debug 选择 增量编译,Adhoc 和 Release 可以选择模块编译

原理可以参考: medium.com/rocket-fuel…

代码优化

swift 设置优化完之后,主要就是代码的优化了。swift 耗时的主要就是类型检查,那么代码优化的重点就是 检查哪些表达式、函数 类型检查占用太长时间。

可以用工具 Swift BuildTimeAnalyzer tool 来查看每一个文件的编译时长。

在网上查了各种说法,下面是 swift 代码优化的重点,也确实有用。

  • 闭包和 lazy

不推荐

private(set) lazy var chartViewColors: [UIColor] = [
    self.chartColor,
    UIColor(red: 86/255, green: 84/255, blue: 124/255, alpha: 1),
    UIColor(red: 80/255, green: 88/255, blue: 92/255, alpha: 1),
    UIColor(red: 126/255, green: 191/255, blue: 189/255, alpha: 1),
    UIColor(red: 161/255, green: 77/255, blue: 63/255, alpha: 1),
    UIColor(red: 235/255, green: 185/255, blue: 120/255, alpha: 1),
    UIColor(red: 100/255, green: 126/255, blue: 159/255, alpha: 1),
    UIColor(red: 160/255, green: 209/255, blue: 109/255, alpha: 1),
    self.backgroundGradientView.upperColor
]

推荐:

// Cumulative build time: 56.3ms
private(set) lazy var chartViewColors: [UIColor] = self.createChartViewColors()

// Build time: 6.2ms
private func createChartViewColors() -> [UIColor] {
    return [
        chartColor,
        UIColor(red: 86/255, green: 84/255, blue: 124/255, alpha: 1),
        UIColor(red: 80/255, green: 88/255, blue: 92/255, alpha: 1),
        UIColor(red: 126/255, green: 191/255, blue: 189/255, alpha: 1),
        UIColor(red: 161/255, green: 77/255, blue: 63/255, alpha: 1),
        UIColor(red: 235/255, green: 185/255, blue: 120/255, alpha: 1),
        UIColor(red: 100/255, green: 126/255, blue: 159/255, alpha: 1),
        UIColor(red: 160/255, green: 209/255, blue: 109/255, alpha: 1),
        backgroundGradientView.upperColor
    ]
}
  • ArrayDictionary

集合类型 需要指明类型,并且不要用 + 来合并两个集合

  • 三元运算符 ?:
// Before
return someValue > 3 ? someValue - 2 : someValue + 2

// After
if someValue > 3 {
    return someValue - 2
} else {
    return someValue + 2
}
  • 二元运算符 ??
return CGSize(width: size.width + (rightView?.bounds.width ?? 0) + (leftView?.bounds.width ?? 0) + 22, height: bounds.height)

// After
var padding: CGFloat = 22
if let rightView = rightView {
    padding += rightView.bounds.width
}

if let leftView = leftView {
    padding += leftView.bounds.width
}
return CGSize(width: size.width + padding, height: bounds.height)

?:??都可以通过 条件绑定来解决。

  • 一行表达式不要做太多事情

不要在一个表达式中既做判断,又做计算

if number == 60 * 60 {
    // ...
}

// After
let number: Double = 60 * 60

if number == 3600 {
    // ...
}

代码优化可以参这里

参考