swiftui-expert-skill について
SwiftUI の実装、レビュー、パフォーマンス改善、Instruments のトレース分析を支援するコーディングエージェント向けスキルです。API 指針やトピック別の参考資料も備えています。
主な機能
- 01SwiftUI の実装とレビュー指針
- 02非推奨 API の検索と移行
- 03パフォーマンスと状態管理の実践
- 04Instruments トレースの記録と分析
- 05トピック別参考資料への案内
活用シーン
- 01SwiftUI コードの正確性レビュー
- 02SwiftUI 機能の実装
- 03トレースによる性能問題の調査
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ avdlee/ swiftui-agent-skill --skill swiftui-expert-skillインストール後、Claude Code で/swiftui-expert-skillを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
agents/openai.yamlassets/logo.svgreferences/accessibility-patterns.mdanimation-advanced.mdanimation-basics.mdanimation-transitions.mdcharts-accessibility.mdcharts.mddocument-apps.mdenvironment-patterns.mdfocus-patterns.mdimage-optimization.mdiphone-duo.mdlatest-apis.mdlayout-best-practices.mdliquid-glass.mdlist-patterns.mdlocalization.mdmacos-scenes.mdmacos-views.mdmacos-window-styling.mdmodifier-patterns.mdperformance-patterns.mdpreviews.mdscroll-patterns.mdsheet-navigation-patterns.mdsoft-deprecation.mdstate-management.mdstyled-text-editing.mdtext-patterns.md詳細
SwiftUI エキスパートスキル
運用ルール
- 各
View型を無効化の境界として扱います。その型には読み取るデータだけを渡し、頻繁に変化する依存関係は、影響を受ける最小のサブツリーに近い場所に保ちます - API の使用方法を記述、レビュー、または移行する際は、
references/latest-apis.mdを確認します。タスクに関連する API だけを調べます - すでに非推奨の API は、最新の同等 API に置き換えます。機能の実装中に非推奨になりつつある API を見つけた場合は、指摘したうえでそのまま残します(
references/soft-deprecation.mdを参照) - ブリッジが必要な場合を除き、UIKit/AppKit とのブリッジよりネイティブの SwiftUI API を優先します
- 正確性とパフォーマンスに重点を置き、特定のアーキテクチャ(MVVM、VIPER など)を強制しません
- テストしやすくするため、ビジネスロジックとビューを分離することを推奨しますが、その方法は指定しません
- Apple の Human Interface Guidelines と 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 に置き換えます。非推奨になりつつある API は指摘し、機能の実装中には書き換えません - 処理頻度の高い箇所をリファクタリングして、不要な状態更新を減らします
- 複雑なビュー本体を個別のサブビューに切り出します
UIImage(data:)が使われている場合は、画像のダウンサンプリングを提案します(任意の最適化です。references/image-optimization.mdを参照)
新しい SwiftUI 機能を実装する
- まずデータフローを設計し、所有する状態と注入される状態を特定します
- 差分計算が最適になるようビューを構成します(早い段階でサブビューを切り出します)
- 適切なアニメーションパターン(暗黙的アニメーションと明示的アニメーション、トランジション)を適用します
- タップ可能な要素にはすべて
Buttonを使用し、アクセシビリティのグループ化とラベルを追加します - バージョン固有の API は
#availableで条件分岐し、フォールバックを用意します
新しい Instruments トレースを記録する
ユーザーが「トレースを記録して」「アプリをプロファイルして」「セッションをキャプチャして」などと依頼した場合に実行します。完全なリファレンス:references/trace-recording.md。
- 対象を確認する — 起動中のアプリに接続するか、アプリを起動するか、すべてのプロセスを記録するかを確認します。ユーザーが指定していない場合は尋ねてください。必要に応じて、接続されているデバイスを一覧表示します。
python3 "${SKILL_DIR}/scripts/record_trace.py" --list-devices - 対象の種類に応じてテンプレートを選ぶ —
SwiftUIテンプレートは、実機(物理的な iOS/iPadOS デバイス、またはホストの Mac)で SwiftUI レーンを表示します。例外は iOS Simulator のみで、この場合は 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。分析の組み立て方の概要:
- 分析範囲を決める。 トレース全体を分析するのか、一部を分析するのかを確認します。
- 「X に注目して/X の後/X と Y の間/X の間」→ まず時間範囲を特定します(手順 2 を参照)。
- 範囲を示す手がかりがない場合は、トレース全体を分析します。
- 時間範囲を特定する(ユーザーが範囲を指定した場合のみ)。 パーサーには、次の 2 つの検出モードがあります。
どちらのモードも、# Find a log that marks the start/end of the region of interest: python3 "${SKILL_DIR}/scripts/analyze_trace.py" --trace <path> \ --list-logs --log-message-contains "loaded feed" --log-limit 5 # Or list os_signpost intervals (paired begin/end), filterable by name: 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(サインポストの場合)を選びます。--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のエントリは、構造的な無効化の不具合を示しています。1 つ修正するだけで、多数の下流の高負荷ビューが解消することもあります。
- 相関ごとの
- 特定のビューに高い負荷が示された場合は、何がそのビューを無効化しているのかを確認します。
--fanin-for "<view name>"を使うと、更新を引き起こすソースノードのランキングを取得できます。 - 必要に応じてソースコードで裏付ける。 ユーザーがファイルを指定した場合は、それを読み、ビュー名やユーザーコードのシンボルをファイル内の識別子と照合します。指定がない場合は、SwiftUI が報告したビュー名をもとに、確認するファイルを提案します。
- 優先順位を付けた計画を提示する。 カバレッジ率、高負荷シンボル、重複するビュー、ログのタイムスタンプ、原因グラフのエッジなど、根拠を示し、各提案を Topic Router のリファレンスに案内します。
- ユーザーが編集を依頼した場合にのみ、コードを編集します。
トピックルーター
現在のタスクに関連する各トピックについて、リファレンスファイルを参照してください:
| トピック | リファレンス |
|---|---|
| 状態管理 | references/state-management.md |
環境と @Entry | references/environment-patterns.md |
| ビューの構成 | references/view-structure.md |
| ビューモディファイアとアイデンティティ | references/modifier-patterns.md |
| パフォーマンス | references/performance-patterns.md |
| リストと ForEach | references/list-patterns.md |
| リサイズ可能なレイアウト、セーフエリア、2 カラムのリフロー、折りたたみ式グリッド、アレンジメント、予約領域 | 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として保持しない;意図的な状態の初期値は一度きりであることを文書化する - ビューが所有するオブジェクトには
@StateObject、注入されたものには@ObservedObjectを使用する - iOS 17 以降:
@Observableとともに@Stateを使用する;バインディングが必要な注入されたオブザーバブルには@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が存在する - プレビューは自己完結型のモックデータを使用する;ライブサービスやネットワークに依存しない
コメント
Markdown 対応