今是昨非

今是昨非

日出江花红胜火,春来江水绿如蓝

iOS Compilation Time Optimization

Background#

Currently, the App project is not large, but the compilation time after cleaning takes more than 200 seconds, which doesn't seem reasonable. Therefore, I started investigating.

Typically, compilation time optimization is divided into three parts:

  • Optimization of Xcode compilation settings
  • Optimization of code or function compilation time
  • Optimization of third-party library compilation time

Here, I will investigate each of these parts one by one.

Implementation#

Optimization of Xcode Compilation Settings#

I am using Xcode 13.4, and according to what I found online, there is no need to set New Build System and Debug Information Format in Build Settings anymore as they are already set to reasonable defaults. As for the Optimization Level setting, although it can improve compilation speed, it is not friendly for debugging. Therefore, I won't make any changes for this optimization. Hence, I haven't made any modifications for this optimization.

Optimization of Code or Function Compilation Time#

This aspect mainly focuses on Swift. First, display the methods that take a long time to compile by adding the following settings to Other Swift Flags in Build Settings. This means that functions that take more than 200ms to compile or type checks that take more than 300ms to compile will display warnings. The value of 200ms is set by myself and can be adjusted based on the actual situation of the project:


-Xfrontend -warn-long-function-bodies=200
-Xfrontend -warn-long-expression-type-checking=200

Here are a few modifications I made:

Example of Code to be Optimized 1:


let count: Int = Int((self?.listParamItem.pageSize ?? 0) * ((self?.needRefreshPageNum ?? 0) - 1))
let endIndex = count + Int(self?.listParamItem.pageSize ?? 0) - 1
if (self?.dataList.count ?? 0) > endIndex {

In the above code, the combination of optional chaining and the nil-coalescing operator (??) followed by type conversion makes the code compile slowly, even though the code is correct. These methods take more than 500ms. To optimize them, I modified the code as follows, reducing the compilation time to less than 100ms, which is a 5-fold reduction:


if let self = self {
  let count: Int = self.listParamItem.pageSize * (self.needRefreshPageNum - 1)
  let endIndex: Int = count + self.listParamItem.pageSize - 1
  if self.dataList.count > endIndex {
}

Example of Code to be Optimized 2:


let dic = [
    "aaa": xxx ?? yyy, 
    "bbb": ["ccc": "xxx", "eee": 5],
    "ddd": 5
]

In the above code, there doesn't seem to be any problem, but the compilation time exceeds 200ms, possibly due to type inference. After modifying the code as follows, the compilation time no longer exceeds 200ms:


var dic1: [String: Any] = [:]
dic1["ccc"] = "xxx"
dic1["eee"] = 5

var dic2: [String: Any] = [:]
dic2["aaa"] = xxx
dic2["bbb"] = dic1
dic2["ddd"] = 5

Example of Code to be Optimized 3:


if type == .aaa ||
type == .bbb ||
type == .ccc ||
type == .ddd ||
type == .eee ||
type == .xxx {
  doSomething()
} else {
    doAnotherThing()
}

The above code is not only inelegant but also takes a long time to compile. After modifying it to use Switch case, the code becomes:


switch type {
case .aaa,
.bbb,
.ccc,
.ddd,
.eee,
.xxx: 
  doSomething()
default:
    doAnotherThing()
}

Example of Code to be Optimized 4:


let fontAdd: CGFloat = 14.0

protocolBtn.snp.makeConstraints { make in
    make.left.equalTo(agreeLabel.snp.right).offset(1)
    make.centerY.equalTo(checkBtn.snp.centerY)
    make.width.equalTo(kTransitionW(150 + fontAdd * 10))
}

In the above code, there is a mixture of floating-point and integer arithmetic, which requires Swift to infer whether a floating-point or integer result is needed. After modifying it as follows, the compilation timeout warning disappears:


let fontAdd: CGFloat = 14.0
let width: CGFloat = 150.0 + fontAdd * 10.0

protocolBtn.snp.makeConstraints { make in
    make.left.equalTo(agreeLabel.snp.right).offset(1.0)
    make.centerY.equalTo(checkBtn.snp.centerY)
    make.width.equalTo(kTransitionW(width))
}

Finally, there is a category of methods that are particularly long, which also triggers compilation timeout warnings. To solve this, split the methods into multiple sub-methods.

Optimization of Third-Party Library Compilation Time#

The third-party libraries integrated into the project are all integrated using CocoaPods. Therefore, after each clean build, the third-party libraries will be recompiled. To display the compilation time in Xcode, open the terminal and run the following command, then restart Xcode.


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

Then clean and rebuild the project. You can see detailed compilation times like the following:

Compilation Time

Here, ZLPhotoBrowser is a third-party library installed through Pod. You can see that the compilation of this library's source files took 30 seconds... This page provides detailed information about the compilation time of each library and the project. For third-party libraries with long compilation times, consider importing them using Carthage instead. You can refer to Carthage Usage. Carthage downloads and compiles the third-party libraries into xcframework, which can then be imported into the project. Therefore, it does not need to be recompiled after each clean build, saving compilation time.

Summary#

The three parts of compilation time optimization can be summarized as follows:

  • Optimization of Xcode compilation settings - No need to set in newer versions of Xcode.
  • Optimization of code or function compilation time - Pay attention to optimizing type inference, complex calculations, and the use of operators. However, not all code that exceeds the compilation timeout needs to be optimized. It is a balance between compilation optimization and code simplicity, elegance, and Swift features. You need to choose the right balance.
  • Optimization of third-party library compilation time - This optimization is recommended. For third-party libraries that will not be modified, switch to importing them using Carthage. This can reduce the compilation time.

It is recommended to analyze where the project's compilation time is stuck before optimization, whether it is due to long compilation times of third-party libraries or source files of the project. This will help determine whether to focus on step two or step three.

References#

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.