Xcode10でNew Build Systemになってから、全体的にビルド時間は短くなりました。
しかし、それでも諸々の原因によりビルドがめちゃくちゃ遅い場合があります。
そんな場合でも、キレずに冷静に改善する方法紹介します。
ビルド時間の計測方法
Xcodeの上部にビルド時間を表示するために、ターミナルで
defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES
を実行します。
ステップごとのビルド時間を計測するには、Product > Perform Action > Build With Timing Summary
を実行します。
xcodebuild
の場合は、-showBuildTimingSummary
をつけます。
xcodebuild clean build -project ColorStock.xcodeproj -scheme ColorStock -destination="platform=iOS Simulator,name=iPhone 8" -showBuildTimingSummary
出力はこのようになります。
Build Timing Summary CompileSwiftSources (1 task) | 5.000 seconds PhaseScriptExecution (1 task) | 3.000 seconds CompileStoryboard (2 tasks) | 2.000 seconds ... ** BUILD SUCCEEDED **
大まかにどこに時間がかかっているかがわかります。
まんべんなくかかってたら諦めるしか無い
ビルド設定の見直し
New Build Systemの利用
Xcode10から新しいビルドシステムが採用されているので、そちらを利用します。
旧来のビルドシステムとは違い、並列ビルドをしてくれるので、IDEBuildOperationMaxNumberOfConcurrentCompileTasks
の指定は不要になります。
こちらをすでに設定している場合、そちらが優先されてしまうので、無効にしておきます。
defaults delete com.apple.dt.Xcode IDEBuildOperationMaxNumberOfConcurrentCompileTasks
CocoaPodsのライブラリも並列ビルドしてくれます。
最適化の設定変更
最適化はデバッグ時には必要ないので、Optimization Levelは-O0
にします。
ライブラリ管理の見直し
CocoaPodsからCarthageに移行する
CocoaPodsを使っている場合、Carthageに切り替えることで、ライブラリのfetchと同時にframework
のビルドを行ってくれるため、その分の時間を節約できます。
特に、クリーンビルドの場合、CocoaPodsで導入したライブラリは、再度ビルドし直しになってしまうので、かなり時間がかかってしまいます。
CocoaPodsのプレビルド
ライブラリが多すぎて断念しましたが、Carthageが使えないライブラリの場合、Pods.xcodeproj
を別にビルドして、framework
化してリンクする方法もあります。
未使用コードやアセットの削除
未使用コードの削除
periphery
というOSSで、Swift限定ですが、使われていないコードを検知することが出来ます。
複雑な書き方をしている部分は誤検出が多々あるので、一つずつCall Hierarchy
やシンボル検索でたどっていくことをおすすめします。
未使用アセットの削除
こちらもFengNiao
というOSSで検知することができます。
やはりこちらも誤検出があるので、確認が必要です。
バイナリサイズも小さくなります。
コードの書き方の改善
Swiftは言語として非常に高機能ですが、便利な機能とトレードオフでビルド時間が増加することがあります。
とくに、型推論は時間がかかることが多く、演算の途中では型が確定しないような書き方をすると遅くなることがあります。
CompileSwift
に時間が取られている場合、ここを改善することで多少ビルド時間が短くなることがあります。
メソッドごとのビルド時間の計測
メソッドごとのビルド時間を測るには、ビルドオプションのOther Swift Flagsに-Xfrontend -debug-time-function-bodies
を追加します。
xcodebuild
の場合、OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-function-bodies"
で計測することが出来ます。
計測した時間を集計するには、xcactivitylog
から拾ってくるか、xcodebuild
を使う必要があります。
👇測定用のPythonスクリプトの例です https://github.com/Scior/SBTProfiler/blob/master/src/profiler.py
👹シェル芸 scior.hatenablog.com
コンパイルが長くなるケース
細かいケースは割愛しますが、配列やString
の+
結合や、nil coalescing operator、genericsなどはコンパイルが長くなる場合があります。
以下、遅くなるようなコードの例です。
Stringの+
結合
let hoge: String? = "hoge" let fuga: String? = "fuga" let result = "Hello, " + (hoge ?? "") + "and " + (fuga ?? "")
特にnil coalescing operatorと組み合わせると遅くなるので、一気に結合しないほうがよいです。
CGFloat
の演算
let height = (hogeHeight - inset * 2) / 2
let height: CGFloat
のようにあらかじめ型を明示することで改善することが多いです。
map
などのgenericメソッド
let array = [1 ,3 ,7, 9] let result = array.map { num in // 複雑な処理 }
num -> Hoge
のように戻り値の型明示すると改善します。
そもそもビルドしない
最近良くやりますが、ちょっとの修正の場合、毎回ビルドしないで、LLDBで書き換える方法もあります。
万策尽きたら
28コアのMac Proを買えばいいんじゃないかな🤔