【iOS】ビルド時間を計測する方法!コンパイルの短縮とBuild Time Analyzer for Xcodeの導入

この記事からわかること
- Xcodeでビルド時間(コンパイル)を計測する方法
- Build Time Analyzer for Xcodeの導入と使い方
- コードベースでの原因
index
[open]
\ アプリをリリースしました /
環境
- Xcode:16.0
- iOS:18.0
- Swift:5.9
- macOS:Sonoma 14.6.1
ビルド(コンパイル)時間を計測する
Xcodeプロジェクトで大規模なプロジェクトになってくるとビルドを実行した際のコンパイルに時間がかかってくるようになることがあります。コンパイルに時間がかかるようになる原因はいくつかあり、それは後述していますが、実際にどのファイルのどのメソッドで時間がかかっているかを特定するのは手作業では難しいものがあります。
そこで「コンパイルに時間のかかっている箇所を特定」する方法として以下の2つを紹介します。
- Build SettingsのOther Swift Flagsにフラグを追加
- Build Time Analyzer for Xcode
Build SettingsのOther Swift Flagsにフラグを追加
1つ目の方法はXcodeにデフォルトで備わっているビルド設定を使用する方法です。ターゲットの「Build Settings」>「Other Swift Flags」に-Xfrontend -warn-long-function-bodies={ms}
を定義します。{ms}
の部分は警告を表示したいコンパイル時間を指定すればOKです。

あとは通常通りにビルドするだけで時間に引っかかったメソッドに対してXcodeの警告(黄色いエラー)が表示されるようになり、実際にコンパイルするのに要した時間がミリ秒単位で表示されるようになります。

Instance method 'methodB()' took 57ms to type-check (limit: 10ms)
Build Time Analyzer for Xcode
ビルド(コンパイル)時間を計測する2つ目の方法は「Build Time Analyzer for Xcode」というmacOSツールを使用する方法です。無料でインストールできビルド(コンパイル)時間の計測結果を詳細に出力することが可能になっています。
導入方法は「GitHubリポジトリ」から「Open with Xcode」をクリックするだけです。
Build Time Analyzer for Xcodeをクローンできたらプロジェクトを立ち上げます。以下のような構成になっていますが特にいじらず「⌘ + b
」で自身のMacにビルドします。

ビルドすると以下のような画面が立ち上がります。

ビルド時間計測のためにやるべき手順は以下の通りです。
- Build Time Analyzer for Xcodeをビルドする
- 計測したいプロジェクトにフラグを定義
- 計測したいプロジェクトをClean Build
- 計測したいプロジェクトをビルド
- ツールに表示されているプロジェクト名をタップ
計測対象のプロジェクトにフラグを定義します。ターゲットの「Build Settings」>「Other Swift Flags」に-Xfrontend -debug-time-function-bodies
を定義します。

あとは一度Clean Buildを実行してからビルド「⌘ + b
」を実行すれば「Alternatively, choose an existing project」部分の日時が更新されるのでそのプロジェクトをクリックすると詳細なログ画面に遷移することができます。
一番左にコンパイルにかかった時間がミリ秒単位で表示され、該当クラスやメソッド名、行番号など詳細な情報が確認できるようになります。タップすることで該当ファイルへ遷移することもできるので非常に便利な機能です。

Ensure the Swift compiler flags has been added.
上記の手順を踏んでいたはずなのに以下のようなエラーが発生して、詳細な計測ができない場合がありました。
Ensure the Swift compiler flags has been added.
原因は不明ですがDerivedData
周りかなと思うので一旦以下コマンドで削除してみたところ無事動作するようになりました。
$ rm -rf ~/Library/Developer/Xcode/DerivedData/*
コンパイルに時間のかかる原因
Swiftでコンパイルに時間がかかる主な原因は大きく2つです。
- 型推論
- 複雑な式
他にもファイル内に複数のクラスを定義しないようにしたりすることでもコンパイル時間の短縮にはなるようです。
型推論
Swiftの便利な機能として「型推論」があります。これは変数の定義時などに明確に型名を記述しなくてもコンパイラが適切な型を推測してくれるという機能です。それ以外にもジェネリクスなどを使用した場合など、型が明確になっていない場合はコンパイル時間を遅くする原因の大きな1つになります。
例えば以下のような実装の場合に明確に型定義をしている場合としていない場合でコンパイル時間に差が出てきます。
// 25ms
let result = [1, 2, 3].map { String($0) }.joined(separator: "-").prefix(while: { $0 != "-" })
// 3ms
let result: Substring = [1, 2, 3].map { String($0) }.joined(separator: "-").prefix(while: { $0 != "-" })
複雑な式
Swiftの演算子(+、-、*、/、&&、||、??
)などを複数組み合わせた式などもコンパイル時間を遅くする原因の大きな1つとなります。コンパイル時間を回避するためには明確に型を定義するのはもちろんのこと、式が複雑化しないような工夫や分割をすることでコンパイル時間を短縮することができます。
// 14ms
let ary = [1,2,3]
let sumAry = ary + ary + ary + ary + ary + ary + ary
// 4ms
let ary = [1,2,3]
let sumAry: [Int] = ary + ary + ary + ary + ary + ary + ary
// 2ms
let ary = [1, 2, 3]
let sumAry = Array(repeating: ary, count: 7).flatMap { $0 }
// 1ms
let ary = [1, 2, 3]
let partial = ary + ary
let sumAry = partial + partial + partial
??
を使用しての文字連結なども特にコンパイル時間がかかる大きな原因になります。こちらも明確に型を指定してあげることでグッと早くすることが可能です。
// 50ms
let str: String? = "AAAA"
let sumStr = (str ?? "") + (str ?? "") + (str ?? "")
// 37ms
let str: String? = "AAAA"
let sumStr: String = (str ?? "") + (str ?? "") + (str ?? "")
// 1ms
let str: String? = "AAAA"
let sumStr = (str ?? "" as String) + (str ?? "" as String) + (str ?? "" as String)
dSYMファイルが生成されないようにする
Swiftのコード観点ではなくデバッグモード時にdSYMファイルが生成されないようにしておくこともコンパイル時間を短縮する1つの方法になります。DWARF with dSYM File
が指定されていると生成されてしまうのでDebug
だけDWARF
にしておけば生成されなくなります。

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。