SwiftUIエキスパートスキル は何をしますか?
運用ルール
- 各
View型は無効化境界(invalidation boundary)として扱い、ビューが読み取るデータのみを渡し、頻繁に変更される依存関係は影響が最も小さいサブツリーの近くに配置する - APIの使用、レビュー、移行時は
references/latest-apis.mdを検索し、タスクに関連するAPIのみを参照する - ハード非推奨(hard-deprecated)のAPIは最新の同等品に置き換える。機能開発中はソフト非推奨(soft-deprecated)のAPIにフラグを立て、そのまま残す(
references/soft-deprecation.md参照) - ブリッジングが絶対に必要でない限り、ネイティブのSwiftUI APIをUIKit/AppKitブリッジより優先する
- 正確性とパフォーマンスに注力する;特定のアーキテクチャ(MVVM、VIPERなど)を強制しない
- テスト容易性のためにビジネスロジックをビューから分離することを推奨するが、その方法を強制しない
- AppleのヒューマンインターフェースガイドラインとAPI設計パターンに従う
- ユーザーから明示的に要求された場合のみLiquid Glassを採用する(
references/liquid-glass.md参照) - パフォーマンス最適化は要件ではなく提案として提示する
- バージョン固有のAPIには、適切なフォールバックと共に
#availableガードを使用する - レイアウトとレンダリング入力については、それを消費するSwiftUIビューに最も近い値を読み取る;プロセス全体の画面状態を代用しない
タスクワークフロー
既存のSwiftUIコードをレビューする
- レビュー対象のコードを読み、該当するトピックを特定する
- 非推奨APIをフラグ付けする(
references/latest-apis.mdと比較);ハード非推奨APIは置き換え、ソフト非推奨APIはユーザーが移行を依頼しない限り書き換えずにフラグを立てる - 該当する各トピックについて、以下のトピックルーターを実行する
- バージョン固有機能に対する
#availableガードとフォールバックパスを検証する - 広範なコードベースレビューの場合、最初に小さなフォーカス領域を特定し、一つずつ提示する;ユーザーがコードベース全体のレビューを要求した場合は、TODOリストに分割する
既存のSwiftUIコードを改善する
- 現在の実装をトピックルーターのトピックに対して監査する
- ハード非推奨APIを
references/latest-apis.mdの最新の同等品に置き換える;ソフト非推奨APIにはフラグを立て、機能開発中は書き換えない - ホットパスをリファクタリングして不要な状態更新を減らす
- 複雑なビュー本体を個別のサブビューに抽出する
UIImage(data:)が使用されている場合、画像のダウンサンプリングを提案する(オプションの最適化、references/image-optimization.md参照)
新しいSwiftUI機能を実装する
- 最初にデータフローを設計する:所有状態と注入状態を特定する
- 最適な差分計算のためにビューを構造化する(早期にサブビューを抽出する)
- 正しいアニメーションパターンを適用する(暗黙的 vs 明示的、トランジション)
- すべてのタップ可能要素に
Buttonを使用する;アクセシビリティのグループ化とラベルを追加する - バージョン固有のAPIを
#availableでガードし、フォールバックを提供する
新しいInstrumentsトレースを記録する
ユーザーが「トレースを記録する」「アプリをプロファイルする」「セッションをキャプチャする」などを依頼したときにトリガーされます。完全なリファレンス:references/trace-recording.md。
- ターゲットを確認する — 実行中のアプリにアタッチするか、アプリを起動するか、全プロセスを記録するか?ユーザーが指定しなかった場合は尋ねる。必要に応じて接続済みデバイスをリスト表示する:
python3 "${SKILL_DIR}/scripts/record_trace.py" --list-devices - ターゲットの種類に基づいてテンプレートを選択する —
SwiftUIテンプレートは実機デバイス(物理iOS/iPadOSデバイスまたはホストMac)上でSwiftUIレーンを設定します。唯一の例外はiOSシミュレーターで、SwiftUIレーンは空で返されます — その場合は--template "Time Profiler"に切り替えます(Time Profiler + Hangsは取得できますが、Animation Hitchesは取得できません)。常に--list-devicesを確認します:simulators種類 →Time Profiler;devices種類(実機デバイスとホストMac) → デフォルトのSwiftUI。完全な判断テーブルはreferences/trace-recording.mdにあります。 - 記録を開始する。エージェント主導のセッションで、ユーザーが「終わったら言う」と言った場合、バックグラウンドで開始し、停止ファイルを使用する:
対話型セッションの場合は、ユーザーに完了時にCtrl+Cを押すように伝えるだけです。python3 "${SKILL_DIR}/scripts/record_trace.py" \ --device "<name|udid>" --attach "<AppName>" \ --stop-file /tmp/stop-trace --output ~/Desktop/session.trace - 停止を合図する — ユーザーがアプリの操作を終えたと言ったら、
touch /tmp/stop-traceを実行します。スクリプトはxctraceをクリーンにSIGINTし、最大60秒間、終了を待ちます。 - 結果のトレースを分析する(以下の「トレース駆動型改善」ワークフローに進む)
トレース駆動型改善(Instruments .traceが提供された場合)
ユーザーのリクエストが.traceファイルを参照するたびにトリガーされます。ターゲットのSwiftUIソースファイルはオプションです — 指定された場合は特定の行を引用し、指定されていない場合はトレースが既に明らかにしているビュー名とシンボルに基づいて、どこを見るべきかを推奨します。
完全なリファレンス:references/trace-analysis.md。
ハング(Hangs): xctrace helpがtriageをリストする場合(Xcode 27.2+)、xctrace triage <trace> --style hangsから開始し、次にxctrace showで詳細を掘り下げます。バンドルされたパーサーは、ヒッチ、SwiftUI更新、原因グラフ、ログまたはsignpostウィンドウに対して引き続きツールとして使用します。
パーサーの構成パターンの概要:
- 分析範囲を設定する。 自問する:ユーザーはトレース全体を望んでいるのか、それとも一部か?
- 「Xに焦点を当てる / Xの後 / XとYの間 / Xの間」 → 最初にウィンドウを解決する(ステップ2参照)。
- 範囲指定の手掛かりがない → トレース全体を分析する。
- ウィンドウを解決する(ユーザーが範囲指定した場合のみ)。 パーサーは2つの発見モードを提供する:
どちらのモードも発見範囲を指定するために# 関心領域の開始/終了を示すログを見つける: python3 "${SKILL_DIR}/scripts/analyze_trace.py" --trace <path> \ --list-logs --log-message-contains "loaded feed" --log-limit 5 # またはos_signpostインターバル(ペアの開始/終了)をリスト表示し、名前でフィルタリング可能: python3 "${SKILL_DIR}/scripts/analyze_trace.py" --trace <path> \ --list-signposts --signpost-name-contains "ImageDecode"--window START_MS:END_MSを受け付けます。ユーザーの説明に一致するtime_ms(ログの場合)またはstart_ms/end_ms(signpostの場合)を選択します。--window 10400:11700のようなウィンドウを構築します。 - メイン分析を実行する(
--windowの有無は問わない):python3 "${SKILL_DIR}/scripts/analyze_trace.py" --trace <path> \ --json-only --top 10 [--window START_MS:END_MS] references/trace-analysis.mdで解釈する — 主要な診断指標:- 各相関関係内の
main_running_coverage_pct(<25% = ブロック済み;≥75% = CPUバウンド)。 swiftui-causes.top_sourcesは、更新が発生し続ける理由を明らかにします —UserDefaultObserver.send()や広範なEnvironmentWriterエントリのような高エッジ数のソースは、構造的な無効化バグです。一つを修正すると、多くの下流のホットビューが縮小することがよくあります。
- 各相関関係内の
- 特定のビューが高コストとして表示された場合、誰がそれを無効化しているかを尋ねます。
--fanin-for "<view name>"を使用して、更新を駆動するソースノードのランク付けされたリストを取得します。 - 必要に応じてソースに基づいて判断します。 ユーザーがファイルを指定した場合はそれを読み、ビュー名やユーザーコードのシンボルをその中の識別子と照合します。指定されていない場合は、SwiftUIが報告したビュー名に基づいて、どのファイルを開くべきかを推奨します。
- 優先順位付きの計画を返します。 証拠(カバレッジ%、ホットシンボル、重複ビュー、ログタイムスタンプ、原因グラフのエッジ)を引用し、各推奨事項をトピックルーターのリファレンスにルーティングします。
- ユーザーが編集を依頼した場合のみコードを編集します。
トピックルーター
現在のタスクに関連する各トピックについて、リファレンスファイルを参照します:
| トピック | リファレンス |
|---|---|
| 状態管理 | references/state-management.md |
環境設定と@Entry(「'@Entry var'にクロージャ/クラス型を格納する」警告を含む) | references/environment-patterns.md |
| ビュー構成 | references/view-structure.md |
| ビューモディファイアと識別性 | references/modifier-patterns.md |
| パフォーマンス | references/performance-patterns.md |
| ListとForEach | references/list-patterns.md |
| リサイズ可能レイアウト、セーフエリア、二段組みリフロー、折りたたみグリッド、配置、予約領域 | references/layout-best-practices.md |
| iPhone Duo、折りたたみデバイス、大画面ディスプレイ(最初に読んで技術を選択) | references/iphone-duo.md |
シート、ナビゲーション、大画面でのNavigationSplitView、タブバー/サイドバー(sidebarAdaptable) | references/sheet-navigation-patterns.md |
| ScrollView、スクロール位置、スクロールジオメトリ | references/scroll-patterns.md |
| フォーカス管理 | references/focus-patterns.md |
| アニメーション(基本) | references/animation-basics.md |
| アニメーション(トランジション) | references/animation-transitions.md |
| アニメーション(高度) | references/animation-advanced.md |
| アクセシビリティ | references/accessibility-patterns.md |
| Swift Charts | references/charts.md |
| チャートのアクセシビリティ | references/charts-accessibility.md |
| 画像最適化と表示スケール | references/image-optimization.md |
| ツールバー | references/toolbar-patterns.md |
| ドキュメントベースアプリ | references/document-apps.md |
| WebKit | references/webkit-integration.md |
| スタイル付きテキスト編集 | references/styled-text-editing.md |
| Liquid Glass(iOS 26+) | references/liquid-glass.md |
| macOSシーン | references/macos-scenes.md |
| macOSウィンドウスタイリング | references/macos-window-styling.md |
| macOSビュー | references/macos-views.md |
| テキストパターン | references/text-patterns.md |
| ローカライゼーション | references/localization.md |
| 非推奨APIルックアップ | references/latest-apis.md |
| ソフト非推奨APIの取り扱い | references/soft-deprecation.md |
| プレビュー | references/previews.md |
| Instrumentsトレース分析 | references/trace-analysis.md |
| Instrumentsトレース記録 | references/trace-recording.md |
正確性チェックリスト
以下は厳格なルールです — 違反は常にバグです:
-
@Stateプロパティはprivateである -
@Bindingは、子が親の状態を変更する場合にのみ使用する - 親が所有する変更可能な入力は
@State/@StateObjectとして保存しない;意図的な初期状態の種は、1回限りとして文書化する - ビューが所有するオブジェクトには
@StateObjectを、注入されたオブジェクトには@ObservedObjectを使用する - iOS 17+:
@Stateは@Observableと共に;バインディングが必要な注入されたObservableには@Bindableを使用する -
ForEachは安定した識別子を使用する(.indices/\.offsetは決して使用しない;idはビューよりも長く存続し、可変コンテンツから導出されない) -
ForEach要素あたりのビュー数は一定;List行は単項である - カスタム
@Environment/@FocusedValueキーにクロージャを格納しない - カスタム
@Entryのデフォルト値は安定している(Model()/Date()/UUID()式を使用しない) - SwiftUIの表示スケールは
@Environment(\.displayScale)から取得し、グローバルな画面状態からは取得しない - セーフエリアコンテンツは
GeometryProxy.safeAreaInsetsを二重に適用しない -
.animation(_:value:)は常にvalueパラメータを含める -
@FocusStateプロパティはprivateである -
.focusable()ビュー上のタップジェスチャーハンドラ内での冗長な@FocusState書き込みがない - バージョン固有のAPIは
#availableでガードされ、適切なフォールバックがある - チャート型を使用するファイルには
import Chartsが存在する - プレビューは自己完結型のモックデータを使用する;ライブサービスやネットワークに依存しない