swiftui-performance-audit について
コードレビューと Instruments のトレースを使って SwiftUI の性能を診断・改善するスキルです。開発者が原因の特定、修正、修正前後の検証を進められるよう支援します。
主な機能
- 01コード中心の性能レビュー
- 02Instruments による計測ガイド
- 03トレースに基づく診断
- 04対象を絞った修正案
- 05ベースラインとの比較
活用シーン
- 01SwiftUI のスクロールや画面遷移の遅さを調査
- 02ビューの body 内の高負荷処理を特定
- 03修正前後の性能を比較
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dagba/ ios-mcp --skill swiftui-performance-auditインストール後、Claude Code で/swiftui-performance-auditを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/demystify-swiftui-performance-wwdc23.mdoptimizing-swiftui-performance-instruments.mdunderstanding-hangs-in-your-app.mdunderstanding-improving-swiftui-performance.md詳細
SwiftUI パフォーマンス監査
概要
計測とベースラインの作成から、根本原因の分析、具体的な改善策まで、SwiftUI のビューのパフォーマンスをエンドツーエンドで監査します。
ワークフローの判断ツリー
- ユーザーがコードを提示した場合は、「コード優先レビュー」から始めます。
- ユーザーが症状のみを説明した場合は、最小限のコードとコンテキストを求めてから、「コード優先レビュー」を行います。
- コードレビューで結論が出ない場合は、「ユーザーによるプロファイリングを支援する」に進み、トレースまたはスクリーンショットを依頼します。
1. コード優先レビュー
収集する情報:
- 対象のビュー/機能のコード。
- データフロー:状態、環境、監視対象のモデル。
- 症状と再現手順。
注目する点:
- 広範囲な状態変更によるビューの無効化の頻発。
- リスト内の不安定な ID(
idの頻繁な変更、レンダリングごとのUUID())。 body内の負荷の高い処理(フォーマット、ソート、画像のデコード)。- レイアウトの頻繁な再計算(深いスタック、
GeometryReader、Preference の連鎖)。 - ダウンサンプリングやサイズ変更をしていない大きな画像。
- アニメーションが過剰な階層(大きなビュー階層に対する暗黙のアニメーション)。
提示する内容:
- コード上の箇所を示した、考えられる根本原因。
- 推奨する修正とリファクタリング。
- 必要に応じて、最小限の再現コードまたは計測方法の提案。
2. ユーザーによるプロファイリングを支援する
Instruments を使ったデータ収集方法を説明します:
- Instruments で SwiftUI テンプレートを使用します(Release ビルド)。
- 対象の操作(スクロール、画面遷移、アニメーション)を正確に再現します。
- SwiftUI のタイムラインと Time Profiler を記録します。
- 関連するレーンとコールツリーをエクスポートするか、スクリーンショットを撮ります。
依頼する情報:
- トレースのエクスポート、または SwiftUI のレーンと Time Profiler のコールツリーのスクリーンショット。
- デバイス/OS/ビルド構成。
3. 分析と診断
SwiftUI でよく見られる原因を優先的に確認します:
- 広範囲な状態変更によるビューの無効化の頻発。
- リスト内の不安定な ID(
idの頻繁な変更、レンダリングごとのUUID())。 body内の負荷の高い処理(フォーマット、ソート、画像のデコード)。- レイアウトの頻繁な再計算(深いスタック、
GeometryReader、Preference の連鎖)。 - ダウンサンプリングやサイズ変更をしていない大きな画像。
- アニメーションが過剰な階層(大きなビュー階層に対する暗黙のアニメーション)。
トレースやログの根拠を示して、調査結果をまとめます。
4. 改善
対象を絞った修正を適用します:
- 状態の適用範囲を狭めます(
@State/@Observableを末端のビューに近づけます)。 ForEachとリストの ID を安定させます。- 負荷の高い処理を
bodyの外に移します(事前計算、キャッシュ、@State)。 - 負荷の高いサブツリーには
equatable()または値ラッパーを使用します。 - レンダリング前に画像をダウンサンプリングします。
- レイアウトの複雑さを抑えるか、可能な場合は固定サイズを使用します。
よくあるコードの問題(および修正方法)
コードレビューでは、次のパターンに注目します。
body 内の負荷が高いフォーマッター
var body: some View {
let number = NumberFormatter() // slow allocation
let measure = MeasurementFormatter() // slow allocation
Text(measure.string(from: .init(value: meters, unit: .meters)))
}
モデルまたは専用のヘルパーでフォーマッターをキャッシュすることを推奨します:
final class DistanceFormatter {
static let shared = DistanceFormatter()
let number = NumberFormatter()
let measure = MeasurementFormatter()
}
負荷の高い処理を行う計算プロパティ
var filtered: [Item] {
items.filter { $0.isEnabled } // runs on every body eval
}
変更時に事前計算するか、キャッシュすることを推奨します:
@State private var filtered: [Item] = []
// update filtered when inputs change
body または ForEach 内でのソート/フィルタリング
List {
ForEach(items.sorted(by: sortRule)) { item in
Row(item)
}
}
ビューの更新前に一度だけソートすることを推奨します:
let sortedItems = items.sorted(by: sortRule)
ForEach 内でのインラインフィルタリング
ForEach(items.filter { $0.isEnabled }) { item in
Row(item)
}
ID が安定したフィルタリング済みのコレクションを推奨します。
不安定な ID
ForEach(items, id: \.self) { item in
Row(item)
}
安定しない値には id: \.self を使用せず、安定した ID を使用します。
メインスレッドでの画像デコード
Image(uiImage: UIImage(data: data)!)
メインスレッド以外でデコード/ダウンサンプリングし、結果を保存することを推奨します。
監視対象モデルの広範な依存関係
@Observable class Model {
var items: [Item] = []
}
var body: some View {
Row(isFavorite: model.items.contains(item))
}
更新の波及範囲を抑えるため、粒度の細かいビューモデルまたは項目ごとの状態を推奨します。
5. 検証
同じ記録を再度実行し、ベースラインの指標と比較するようユーザーに依頼します。 データが提供された場合は、差分(CPU、フレーム落ち、メモリのピーク)をまとめます。
出力
以下を提示します:
- 簡潔な指標の表(利用可能な場合は修正前/修正後)。
- 影響の大きい順に並べた主な問題。
- 推定工数を添えた修正案。
参考資料
ユーザーから提供された Apple のドキュメントや WWDC のリソースは、references/ の下に追加します。
- Instruments を使った SwiftUI のパフォーマンス最適化:
references/optimizing-swiftui-performance-instruments.md - SwiftUI のパフォーマンスを理解して改善する:
references/understanding-improving-swiftui-performance.md - アプリのハングを理解する:
references/understanding-hangs-in-your-app.md - SwiftUI のパフォーマンスを解き明かす(WWDC23):
references/demystify-swiftui-performance-wwdc23.md