219

Xcode 6 Beta 6 を使用しています。

これはしばらくの間私を悩ませてきたものですが、今ではほとんど使用できないところまで来ています.

私のプロジェクトは、65 個の Swift ファイルといくつかのブリッジされた Objective-C ファイル (実際には問題の原因ではありません)という適切なサイズになり始めています。

Swift ファイルをわずかに変更すると (アプリでほとんど使用されないクラスに単純な空白を追加するなど)、指定されたターゲットの Swift ファイル全体が再コンパイルされるようです。

詳細な調査の結果、コンパイラ時間のほぼ 100% を占めているのは、CompileSwiftXcode がswiftcターゲットのすべての Swift ファイルに対してコマンドを実行するフェーズであることがわかりました。

さらに調査を行ったところ、アプリ デリゲートとデフォルト コントローラーのみを保持すると、コンパイルは非常に高速になりましたが、プロジェクト ファイルをどんどん追加していくと、コンパイル時間が非常に遅くなり始めていました。

現在、65 個のソース ファイルしかないため、毎回コンパイルするのに約 8/10 秒かかります。あまり速くありません。

this oneを除いて、この問題について話している投稿を見たことがありませんが、それは古いバージョンの Xcode 6 でした。

アップデート

AlamofireEulerCryptoSwiftなど、 GitHubでいくつかの Swift プロジェクトを確認しましたが、実際に比較するのに十分な Swift ファイルはありませんでした。適切なサイズで開始されていることがわかった唯一のプロジェクトはSwiftHN でした。ソース ファイルは 12 個しかありませんでしたが、同じことを確認できました。1 つの単純なスペースとプロジェクト全体で再コンパイルが必要でした。わずかな時間 (2/3 秒)。

アナライザーとコンパイルの両方が非常に高速な Objective-C コードと比較すると、これは Swift が大きなプロジェクトを処理できないように感じますが、間違っていることを教えてください。

Xcode 6 Beta 7で更新

それでも何の改善もありません。これはばかげたことになり始めています。Swift に がない#importため、Apple がこれをどのように最適化できるかは本当にわかりません。

Xcode 6.3およびSwift 1.2で更新

Apple はインクリメンタル ビルド(および他の多くのコンパイラの最適化) を追加しました。これらの利点を確認するには、コードを Swift 1.2 に移行する必要がありますが、Apple は Xcode 6.3 に移行を支援するツールを追加しました。

ここに画像の説明を入力してください

でも

私のようにすぐに喜ぶな。ビルドをインクリメンタルにするために使用するグラフ ソルバーは、まだ十分に最適化されていません。

まず、関数シグネチャの変更を確認しないため、1 つのメソッドのブロックにスペースを追加すると、そのクラスに依存するすべてのファイルが再コンパイルされます。

第二に、変更がファイルに影響を与えなくても、再コンパイルされたファイルに基づいてツリーを作成するようです。たとえば、これら 3 つのクラスを別のファイルに移動すると、

class FileA: NSObject {
    var foo:String?
}
class FileB: NSObject {
    var bar:FileA?
}
class FileC: NSObject {
    var baz:FileB?
}

を変更するFileAと、コンパイラは明らかに再コンパイルするようにマークFileAします。また、再コンパイルされますFileB( への変更に基づいて問題ありません)FileAFileCコンパイルされるため、ここでは決して使用されないFileBため、かなり悪いです。FileCFileA

だから、彼らがその依存関係ツリー ソルバーを改善してくれることを願っています...このサンプル コードでレーダーを開きました。

UPDATE Xcode 7ベータ5およびSwift 2.0で

昨日、Apple はベータ 5 をリリースし、リリース ノートには次のように記載されていました。

Swift 言語とコンパイラ • インクリメンタル ビルド: 関数の本体だけを変更しても、依存ファイルが再ビルドされることはなくなりました。(15352929)

私はそれを試してみましたが、今では本当に (本当に!) うまく機能していると言わざるを得ません. 彼らは、swift のインクリメンタル ビルドを大幅に最適化しました。

swift2.0XCode 7 ベータ 5 を使用してブランチを作成し、コードを最新の状態に保つことを強くお勧めします。

Xcode 8.2で更新

この問題に関する私の最後の更新からしばらく経っているので、ここにあります。

私たちのアプリは現在、ほぼ 20,000 行の Swift コードのみで構成されています。Swift 2 と Swift 3 の移行を受けました。2014 年半ばの Macbook pro (2.5 GHz Intel Core i7) でコンパイルするには約 5/6m かかりますが、クリーン ビルドでは問題ありません。

ただし、Apple が次のように主張しているにもかかわらず、インクリメンタル ビルドはまだ冗談です。

小さな変更のみが発生した場合、Xcode はターゲット全体を再構築しません。(28892475)

明らかに、私たちの多くは、このナンセンスをチェックした後に笑っただけだと思います (プロジェクトの任意のファイルに 1 つのプライベート (プライベート!) プロパティを追加すると、すべてが再コンパイルされます...)

この問題に関する詳細情報が記載されている Apple 開発者フォーラムのこのスレッドを皆さんに紹介したいと思います(また、この問題に関する Apple 開発者のコ​​ミュニケーションに感謝します)。

基本的に、人々はインクリメンタル ビルドを改善するためにいくつかのことを考え出しました。

  1. HEADER_MAP_USES_VFSプロジェクト設定セットを追加true
  2. Find implicit dependenciesスキームから無効にする
  3. 新しいプロジェクトを作成し、ファイル階層を新しいプロジェクトに移動します。

解決策 3 を試してみますが、解決策 1/2 はうまくいきませんでした。

この全体的な状況で皮肉なことに面白いのは、この問題に関する最初の投稿を見ると、最初のコンパイルの遅延に達したときに、swift 1 または swift 1.1 コードを使用して Xcode 6 を使用していたことです。Apple からの実際の改善にもかかわらず、約 2 年後、状況は Xcode 6 の場合と同じくらい悪いです。なんと皮肉なことでしょう。

私たちのプロジェクトに Obj/C ではなく Swift を選んだことを本当に後悔しています。(私は AppCode に切り替えますが、それは別の話です)

とにかく、この記事を書いている時点で、この SO の投稿には 32,000 回以上のビューと 143 回のアップがあるので、私だけではないと思います。この状況について悲観的ではありますが、トンネルの終わりに光があるかもしれません。

時間があれば (そして勇気があれば!)、Apple はこれについてのレーダーを歓迎していると思います。

次回まで!乾杯

Xcode 9で更新

今日これにつまずく。Xcode は、現在のひどいパフォーマンスを改善するために、静かに新しいビルド システムを導入しました。ワークスペース設定で有効にする必要があります。

ここに画像の説明を入力

まだ試していますが、完了後にこの投稿を更新します。しかし、有望に見えます。

4

22 に答える 22

71

さて、ロブ・ネイピアが正しかったことが判明しました。コンパイラが異常終了する原因となったのは、1 つのファイル (実際には 1 つのメソッド) でした。

誤解しないでください。Swift は毎回すべてのファイルを再コンパイルしますが、Apple がコンパイルするファイルにリアルタイムのコンパイル フィードバックを追加したため、Xcode 6 GM はどの Swift ファイルがコンパイルされているか、およびコンパイルのステータスをリアルタイムで表示するようになりました。このスクリーンショットでわかるように:

ここに画像の説明を入力してください

したがって、これは、どのファイルに時間がかかっているかを知るのに非常に便利です。私の場合、それはこのコードでした:

var dic = super.json().mutableCopy() as NSMutableDictionary
dic.addEntriesFromDictionary([
        "url" : self.url?.absoluteString ?? "",
        "title" : self.title ?? ""
        ])

return dic.copy() as NSDictionary

プロパティtitleのタイプがvar title:String?ではなくであったためNSStringです。に追加すると、コンパイラはおかしくなりましたNSMutableDictionary

次のように変更します。

var dic = super.json().mutableCopy() as NSMutableDictionary
dic.addEntriesFromDictionary([
        "url" : self.url?.absoluteString ?? "",
        "title" : NSString(string: self.title ?? "")
        ])

return dic.copy() as NSDictionary

コンパイルを 10/15 秒 (場合によってはそれ以上) から 1 秒に短縮しました... 驚くべきことです。

于 2014-09-14T12:25:57.993 に答える
29

私の場合、Xcode 7 はまったく違いがありませんでした。コンパイルに数秒かかる複数の関数がありました。

// Build time: 5238.3ms
return CGSize(width: size.width + (rightView?.bounds.width ?? 0) + (leftView?.bounds.width ?? 0) + 22, height: bounds.height)

オプションのラップを解除した後、ビルド時間は99.4%短縮されました。

// Build time: 32.4ms
var padding: CGFloat = 22
if let rightView = rightView {
    padding += rightView.bounds.width
}

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

この投稿この投稿で他の例を参照してください。

Xcode のビルド時間アナライザー

これらの問題が発生しているすべての人にとって便利なXcode プラグインを開発しました。

画像

Swift 3 では改善が行われているようですので、Swift コードがより速くコンパイルされることを願っています。

于 2016-05-20T12:19:38.397 に答える
21

おそらく、Swift コンパイラーを修正することはできませんが、修正できるのはコードです!

Swift コンパイラには、コンパイラがすべての関数をコンパイルするのにかかる正確な時間間隔を出力する隠しオプションがあります: -Xfrontend -debug-time-function-bodies. これにより、コード内のボトルネックを見つけて、コンパイル時間を大幅に改善できます。

ターミナルで以下を単純に実行し、結果を分析します。

xcodebuild -workspace App.xcworkspace -scheme App clean build OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-function-bodies" | grep [1-9].[0-9]ms | sort -nr > culprits.txt

素晴らしい Brian Irace が、Swift のコンパイル時間のプロファイリングに関する素晴らしい記事を書きました。

于 2016-04-14T18:17:41.570 に答える
15

注意すべきことの 1 つは、Swift の型推論エンジンは、入れ子になった型を使用すると非常に遅くなる可能性があることです。時間がかかる個々のコンパイル ユニットのビルド ログを確認し、Xcode によって生成されたコマンド全体をコピーしてターミナル ウィンドウに貼り付け、CTRL-\ を押していくつかの診断。完全な例については、http://blog.impathic.com/post/99647568844/debugging-slow-swift-compile-timesをご覧ください。

于 2014-10-18T16:57:28.957 に答える
7

これらはすべてベータ版であり、Swift コンパイラは (少なくとも今日の時点では) 公開されていないため、あなたの質問に対する本当の答えはないと思います。

まず第一に、Objective-C と Swift コンパイラを比較することは、どこか残酷です。Swift はまだベータ版であり、Apple は機能の提供とバグの修正に取り組んでいると確信しています。Apple はいずれコンパイラを最適化すると思います。

何らかの理由ですべてのソース ファイルを完全にコンパイルする必要がある場合は、個別のモジュール/ライブラリを作成するオプションがあります。ただし、言語が安定するまで Swift はライブラリを許可できないため、このオプションはまだ使用できません。

私の推測では、彼らはコンパイラを最適化するでしょう。プリコンパイルされたモジュールを作成できないのと同じ理由で、コンパイラがすべてをゼロからコンパイルする必要がある可能性があります。しかし、言語が安定したバージョンに達し、バイナリの形式が変更されなくなったら、ライブラリを作成できるようになり、おそらく (?) コンパイラもその作業を最適化できるようになります。

推測ですが、アップルだけが知っています...

于 2014-09-05T16:18:10.543 に答える
4

Swift の配列と辞書の構築は、(特にRubyの背景を持つあなたにとって) 非常に一般的な原因のようです。つまり、

var a = ["a": "b",
         "c": "d",
         "e": "f",
         "g": "h",
         "i": "j",
         "k": "l",
         "m": "n",
         "o": "p",
         "q": "r",
         "s": "t",
         "u": "v",
         "x": "z"]

おそらく、これで修正する必要がある原因になります。

var a = NSMutableDictionary()
a["a"] = "b"
a["c"] = "d"
... and so on
于 2015-04-04T17:27:58.207 に答える
4

コンパイラは、型の推測とチェックに多くの時間を費やします。したがって、型注釈を追加すると、コンパイラが大いに役立ちます。

次のような連鎖関数呼び出しがたくさんある場合

let sum = [1,2,3].map({String($0)}).flatMap({Float($0)}).reduce(0, combine: +)

sum次に、コンパイラは の型がどうあるべきかを判断するのにしばらく時間がかかります。タイプを追加すると役立ちます。また、断続的なステップを個別の変数に入れることも役立ちます。

let numbers: [Int] = [1,2,3]
let strings: [String] = sum.map({String($0)})
let floats: [Float] = strings.flatMap({Float($0)})
let sum: Float = floats.reduce(0, combine: +)

特に数値型CGFloatの場合Int、大いに役立ちます。リテラル数値 like2は、さまざまな数値型を表すことができます。したがって、コンパイラはコンテキストからそれがどれであるかを把握する必要があります。

調べるのに時間がかかる関数+も避けるべきです。複数の配列を連結するために someを使用すると、コンパイラが各 に対してどの実装を呼び出す必要があるかを判断+する必要があるため、処理が遅くなります。したがって、可能であれば代わりにwithを使用してください。++var a: [Foo]append()

Xcode でのコンパイルが遅い関数を検出する警告を追加できます。

ターゲットのビルド設定で、その他の Swift フラグを検索して追加します

-Xfrontend -warn-long-function-bodies=100

コンパイルに 100 ミリ秒以上かかるすべての関数について警告します。

于 2016-12-12T17:42:30.020 に答える
4

デバッグとテストでは、次の設定を使用して、コンパイル時間を約 20 分から 2 分未満に短縮してください。

  1. プロジェクトのビルド設定で、「最適化」を検索して、デバッグを「最速[-O3]」以上にします。
  2. アクティブなアーキテクチャのビルドを設定: はい
  3. デバッグ情報の形式: DWARF
  4. モジュール全体の最適化: いいえ

プロジェクトがビルドされるのを待つのに数え切れないほどの時間を無駄にしましたが、その 1 つの小さな変更を加える必要があり、それをテストするためにさらに 30 分待たなければならなかったことに気づきました。これらは私のために働いた設定です。(設定はまだ試行錯誤中です)

ただし、少なくとも "DWARF with dSYM" (アプリケーションを監視する場合) を設定し、リリース/アーカイブが iTunes Connect にプッシュされるように Build Active Architecture を "NO" に設定してください (ここでも数時間を無駄にしたことを覚えています)。

于 2015-06-30T01:37:25.430 に答える
2

Mac を再起動すると、この問題が驚くほど改善されました。再起動するだけで、15 分のビルドから 30 秒のビルドになりました。

于 2015-07-19T16:52:04.637 に答える
1

新しい Xcode 6.3 でSwift のコンパイル時間が改善されました

コンパイラの改善

Swift 1.2 コンパイラは、より安定し、あらゆる点でパフォーマンスを向上させるように設計されています。これらの変更により、Xcode で Swift を操作する際のエクスペリエンスも向上します。最も目に見える改善のいくつかは次のとおりです。

増分ビルド

変更されていないソース ファイルはデフォルトで再コンパイルされなくなり、ほとんどの一般的なケースでビルド時間が大幅に短縮されます。コードの構造を大幅に変更すると、複数のファイルを再構築する必要が生じる場合があります。

より高速な実行可能ファイル

デバッグ ビルドは、かなり高速に実行されるバイナリを生成し、新しい最適化により、リリース ビルドのパフォーマンスがさらに向上します。

コンパイラ診断の改善

より明確なエラーおよび警告メッセージと、新しい修正プログラムにより、適切な Swift 1.2 コードの記述が容易になります。

安定性の向上

最も一般的なコンパイラのクラッシュが修正されました。また、Xcode エディター内で表示される SourceKit の警告も少なくなります。

于 2015-02-10T00:09:58.360 に答える
0

Xcode 6.3.1では何も機能しませんでした.約100個のSwiftファイルを追加すると、Xcodeがビルドおよび/またはインデックス作成でランダムにハングしました。モジュラー オプションを試しましたが、成功しませんでした。

Xcode 6.4 Beta をインストールして使用すると、実際にうまくいきました。

于 2015-05-15T06:31:43.653 に答える
0

型推論で大幅な速度低下を引き起こす可能性がある別のケースを次に示します。合体演算子

次のような行を変更します。

abs(some_optional_variable ?? 0)

abs((some_optional_variable ?? 0) as VARIABLE_TYPE)

コンパイル時間を 70 秒から 13 秒にするのに役立ちました

于 2015-06-08T15:48:31.267 に答える