performance-audit について
SwiftUI 開発者向けのパフォーマンス監査スキルです。ビューのコードとデータフローから一般的なボトルネックを調べ、必要に応じて Instruments による計測と修正、再検証を案内します。
主な機能
- 01状態変更によるビュー更新の確認
- 02リストの不安定な ID の特定
- 03body 内の高コスト処理の検出
- 04Instruments による計測の案内
- 05修正案とベースライン比較の提示
活用シーン
- 01スクロールや画面遷移の引っ掛かり調査
- 02SwiftUI ビューコードとデータフローの確認
- 03計測結果による最適化の検証
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ patrickserrano/ skills --skill performance-auditインストール後、Claude Code で/performance-auditを入力して読み込まれたか確認します。
詳細
SwiftUI パフォーマンス監査
概要
計測とベースライン設定から、根本原因の分析、具体的な改善手順まで、SwiftUI ビューのパフォーマンスを監査します。
ワークフローの判断ツリー
- ユーザーがコードを提示した場合:コード優先レビューから開始します
- ユーザーが症状のみを説明した場合:最小限のコードとコンテキストを尋ねてから、コード優先レビューを行います
- コードレビューで結論が出ない場合:Instruments を使ったプロファイリングを案内します
1. コード優先レビュー
収集する情報
- 対象のビュー/機能のコード
- データフロー:状態、環境、監視対象のモデル
- 症状と再現手順
確認するポイント
- 広範な状態変更によるビューの無効化の連鎖
- リスト内の不安定な識別性(
idの頻繁な変化、レンダリングごとのUUID()) body内の負荷の高い処理(フォーマット、ソート、画像のデコード)- レイアウトの頻繁な再計算(深いスタック、
GeometryReader、Preference の連鎖) - ダウンサンプリングされていない大きな画像
- 過剰にアニメーションされるビュー階層(大規模なツリーに対する暗黙的なアニメーション)
提示する内容
- コードを参照した根本原因の候補
- 推奨する修正とリファクタリング
- 必要に応じて最小限の再現例または計測方法の提案
2. プロファイリングの案内
コードレビューで結論が出ない場合は、データの収集方法を説明します。
- Instruments の SwiftUI テンプレートを使用します(Release ビルド)
- 問題が起きる操作(スクロール、ナビゲーション、アニメーション)を正確に再現します
- SwiftUI タイムラインと Time Profiler を記録します
- 関連するレーンとコールツリーをエクスポートするか、スクリーンショットを撮ります
以下を依頼します。
- トレースのエクスポートまたはスクリーンショット
- デバイス/OS/ビルド構成
3. よくあるコードの問題点(と修正方法)
body 内の負荷の高いフォーマッター
問題のある例:
var body: some View {
let formatter = NumberFormatter() // Slow allocation every render
Text(formatter.string(from: value))
}
良い例:
final class Formatters {
static let number = NumberFormatter()
}
var body: some View {
Text(Formatters.number.string(from: value))
}
負荷の高い処理を行う計算プロパティ
問題のある例:
var filtered: [Item] {
items.filter { $0.isEnabled } // Runs every body eval
}
良い例:
@State private var filtered: [Item] = []
.onChange(of: items) {
filtered = items.filter { $0.isEnabled }
}
ForEach 内のソート/フィルタリング
問題のある例:
ForEach(items.sorted(by: sortRule)) { item in
Row(item)
}
良い例:
let sortedItems = items.sorted(by: sortRule) // Compute once
ForEach(sortedItems) { item in
Row(item)
}
不安定な識別性
問題のある例:
ForEach(items, id: \.self) { item in // \.self may not be stable
Row(item)
}
良い例:
ForEach(items, id: \.stableID) { item in
Row(item)
}
メインスレッドでの画像デコード
問題のある例:
Image(uiImage: UIImage(data: data)!)
良い例:
// Decode/downsample off main thread, cache the result
@State private var image: UIImage?
.task {
image = await ImageLoader.load(data: data, targetSize: size)
}
監視対象のモデル内の広範な依存関係
問題のある例:
@Observable class Model {
var items: [Item] = []
}
var body: some View {
Row(isFavorite: model.items.contains(item)) // Entire array dependency
}
良い例:
// Granular view models or per-item state to reduce update fan-out
4. 改善策
| 問題 | 修正方法 |
|---|---|
| 広範な状態変更 | @State/@Observable の適用範囲を、より末端のビューに絞ります |
| 不安定な識別子 | ForEach では安定した一意の ID を使用します |
| body 内の負荷の高い処理 | 事前計算、キャッシュ、または @State への移動を行います |
| 負荷の高いサブツリー | equatable() または値型のラッパーを使用します |
| 大きな画像 | 描画前にダウンサンプリングします |
| 複雑なレイアウト | 入れ子を減らし、可能な場合は固定サイズを使用します |
5. 検証
ユーザーに同じ計測を再実行してもらい、ベースラインと比較します。
- CPU 使用率
- フレーム落ち
- メモリのピーク
出力形式
以下を提示します。
- 指標の表(利用可能な場合は修正前/修正後)
- 影響の大きい順に並べた主な問題
- 推定作業量を添えた修正案
プロファイリング用コマンド
# Build for profiling
xcodebuild -scheme MyApp -configuration Release -destination 'platform=iOS Simulator,name=iPhone 15 Pro' build
# Open in Instruments
open -a Instruments
Instruments のチェックリスト
- Debug ではなく Release ビルドを使用する
- SwiftUI テンプレートを選択する
- 問題のある操作を正確に再現する
- SwiftUI タイムラインで body の評価を確認する
- Time Profiler でホットスポットを確認する
- Animation タイムラインでフレームレートの低下を確認する
コメント
Markdown 対応