mcpField
U
uikit-app-modernization

uikit-app-modernization

github.com/tartinerlabs開発8301 回インストール1 日前に更新
リポジトリ

uikit-app-modernization について

Swift または Objective-C の UIKit アプリを対象に、範囲を絞ってモダナイズするスキルです。旧式の共有状態 API やアプリ・シーンのライフサイクルを更新し、サイズ変更可能な UI とマルチウィンドウに対応する際、変更範囲と制御フローの維持を重視します。

主な機能

  1. 01旧式の共有状態 API を置換
  2. 02シーンベースのライフサイクルへ移行
  3. 03サイズ変更可能な UI に対応
  4. 04マルチウィンドウ環境に対応
  5. 05制御フローと変更範囲を維持

活用シーン

  1. 01UIKit アプリをシーンライフサイクルに更新
  2. 02非推奨の画面・向き情報へのアクセスを置換
  3. 03サイズ変更可能なウィンドウ向けにレイアウトを調整
  4. 04無関係な編集を避けるため変更を確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/tartinerlabs/skills --skill uikit-app-modernization

インストール後、Claude Code で/uikit-app-modernizationを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
orientation-task.md
safe-area-task.md
scene-lifecycle-task.md
uiscreen-task.md

詳細

UIKit アプリのモダナイズスキル

目的

UIKit アプリをモダナイズし、最新の iOS で正しく動作するようにします。

  • レガシーな共有状態 API への参照を排除する
  • アプリケーションライフサイクルからシーンライフサイクルへ移行する
  • 動的なシーンサイズとマルチウィンドウ環境に対応する

対象範囲

このスキルは、Swift と Objective-C のコードベースに対して、特定の対象に絞ったモダナイズを行います。

  • レガシーな共有状態 API を、状況に応じた最新の API に置き換える
  • シーンベースのライフサイクルへ移行する
  • 次の使用を取り除いて、アプリをサイズ変更可能なユーザーインターフェースに対応させる:
    • メイン画面(UIScreen.mainScreen、UIScreen.main)
    • インターフェイスの向き(interfaceOrientation)
    • 対称的なセーフエリアを前提とすること(safeAreaLayoutGuide、safeAreaInsets)

基本原則

  1. 利用箇所に最も近いもの — 利用箇所に最も近い情報を優先します(例:ウィンドウのものよりビューの trait collection)。
  2. 対象 API が存在する場合は、必ず置き換えを適用します。 TODO だけでは不十分です。対象 API を含むファイルで差分がない場合も不十分です。 ファイルに対象の非推奨 API が含まれ、現在のタスクの参照ファイルにあるパターンのいずれかに沿って具体的な置き換えが可能なら、適用してください。対象 API がデッドコード(#if 0/#endif)内にのみ現れる場合に限り、スキップできます。有効な置き換えが 2 つあり、どちらにするか迷う場合は、差分なしにするのではなく、ユーザーの依頼に最も合うものを選んでください。ファイルを黙ってスキップしてはいけません。変更を適用しない場合は、可能な選択肢についてユーザーに相談してください。ファイルに対して何も出力しないことは避けてください。単純なファイルでエッジケースの検討にとらわれないでください。置き換えが明白なら適用して次に進んでください。
  3. TODO は実行可能な内容にします。 残す TODO にはそれぞれ、(a)変更が必要な理由、(b)適切な置き換えがどのようなものか、(c)ライフサイクルやスレッドに関する懸念事項を記載してください。TODO は変更していないコードの上に、独立した行として記述してください。曖昧な TODO(「後で修正」など)は、次の担当者が推測できる以上の情報を提供せず、レビューの注意を消費するため、ない方がましです。
  4. 既存の注釈で移行方法がすでに示されている場合、重複する TODO を追加しないでください。 呼び出し箇所に、バグ報告への参照を伴う #pragma clang diagnostic ignored、既存の // TODO、または移行先を示す非推奨コメントがすでにある場合、TODO を重ねて追加しないでください。既存の注釈にない追加の移行ガイダンスを提供する場合に限り、新しい TODO を追加してください。
  5. リスクのあるコード変更を行う前にユーザーに確認し、対話的に確認できない場合に限り TODO を代替策とします。 置き換えによって呼び出し元が壊れたり、観測可能な動作が変わったりするおそれがある場合(例:他のモジュールがインポートするヘッダー内のメソッドシグネチャ変更、左右の向きが重要な場面で向きの代わりに width > height を使うなど)、最初にユーザーへ対応方法を確認してください。スキルが非対話モードで実行されている場合、またはユーザーが確認への回答を明示的に控えた場合に限り、TODO を残して先に進みます。これは、現在のタスクの参照ファイルで指定された標準的な、そのまま置き換え可能な安全な置き換えには適用されません。これらはコア原則 2 に従って必ず適用してください。
  6. 明示的なユーザー指示を優先し、それ以外の場合はタスクの参照ファイルの既定値を適用します。 ユーザーが特定の方法(特定の属性、パラメーター名、パラメーターの位置、trait の取得元、またはフォールバック動作など)を指定した場合は、指定どおりにしてください。自分がより現代的と考える方法に黙って置き換えてはいけません。ユーザーの指示が一般的な場合(「このアプリをモダナイズして」「UIScreen.main の使用箇所を修正して」など)は、現在のタスクの参照ファイルにある既定値を適用してください。
  7. 動的な値をリテラルに置き換えてはいけません — 置き換え後も必ず動的な値を維持してください。
  8. 制御フローを維持します — 元のコード構造を保てる、そのまま置き換え可能な方法を優先してください。直接置き換えられない場合に限り、ガードや早期 return のパターンを追加してください。制御フロー(if/else、switch/case/default、do/catch)の周辺を編集する場合は、編集後も分岐構造が維持されていることを確認してください。ユーザーが明示的に求めていない限り、分岐(} else {、default:、catch)を削除してはいけません。if/else を順次実行にまとめる差分は重大なバグです。両方の分岐が無条件に実行されます。
  9. 対象範囲を守ります。便乗した整理はしません。 現在のタスクの対象となる非推奨 API を含む行だけを変更してください。近くにある別の非推奨 API もついでに修正してはいけません。末尾の空白を削除したり、空行を整形したり、周辺の書式を「整理」したりしないでください。隣接する行に明らかなモダナイズの機会があっても、そのままにしてください。タスクはそれぞれ独立しているため、対象外の編集を加えると、対象内の変更も警告扱いになるおそれがあります。
  10. 繰り返し使われる式を抽出します — 同じ置き換え値を同じスコープ内で複数回使う場合は、名前付きのローカル変数に抽出してください。
  11. グローバルなシーン/ウィンドウ状態をたどってはいけません — 置き換えに UIApplication.shared、UIDevice.current、UIScreen.main などの共有オブジェクトを使ってはいけません。ローカルなオブジェクトを利用できない場合は、メソッドが新しいパラメーターを受け取るように変更し、古いメソッドを非推奨にしてください。
  12. パターンを完全に適用します。部分適用は不可です — 複数の要素からなるパターンは、すべての要素をひとまとまりとして同時に適用してください。非推奨化して転送するパターンでは、非推奨化、新しいオーバーロード、転送のすべてが必要です。メソッド抽出が必要なパターンで、インライン置き換えだけにしてはいけません。現在のタスクで API の置き換えとリアクティブな更新(例:trait の変更監視)の両方が必要な場合、これらはひとまとまりの変更です。片方だけを適用してはいけません。 非推奨化して転送するパターンを、共有オブジェクトをインラインで参照する形に格下げするのは誤りです。呼び出し元が新しい API を見つけるために依存している非推奨ブリッジが削除され、移行方法が気づかれないまま失われます。適切なパラメーター名/型/位置を持つ新しいオーバーロード、共有状態(例:UITraitCollection.current、UIScreen.main)を使って新しいオーバーロードを呼び出す古いメソッド、適切な属性による古いメソッドの非推奨化、非推奨のラッパーの維持という 4 つの要素をすべて完了できない場合は、部分的な変更を適用しないでください。パターンを完全に適用するか、明確な理由を示してスキップしてください。
  13. 新しいオーバーロードを追加しても古いメソッドを削除してはいけません。 非推奨化して転送するパターンを適用する場合、古いメソッドは、.current を使って新しいオーバーロードに転送する非推奨ラッパーとして、必ずファイルに残してください。古いメソッドを削除すると(差分では未使用に見える場合でも)、コードベースから非推奨を示す情報が失われ、移行ブリッジが気づかれないまま削除されます。これは Objective-C のメソッド、Swift のメソッド、Swift のイニシャライザー、計算プロパティ、プロトコル拡張のメソッドに適用されます。新しいオーバーロードを追加する際にメソッドを削除しようとしていることに気づいたら、作業を止めてください。削除ではなく、非推奨属性を付けて残す必要があります。
  14. 無関係なガードやフォールバックを維持します。 UIScreen.mainScreen 参照を削除する場合、変更するのはその参照だけにしてください。呼び出し箇所を囲む respondsToSelector: のチェック、nil スクリーンのガード、if (screen != nil) による防御、バージョンチェック(#available、@available)、その他の防御ロジックも同時に削除してはいけません。ユーザーが明示的に求めた場合は除きます。各ガードには、SDK バージョン間でのセレクターの利用可否、nil のウィンドウに対する安全性、機能フラグなど、独立した理由があります。モダナイズで変更するのは画面から取得する値だけであり、周囲の制御フローではありません。
  15. 非推奨化は、非推奨 API に触れる最も低い階層のメソッドに適用します。 複数の呼び出し元が 1 つのヘルパーに集約され、そのヘルパーが実際に非推奨の共有状態を読み取る場合、非推奨化して転送する処理はすべての公開呼び出し元ではなく、ヘルパーに適用してください。ヘルパーだけがパラメーターを必要とするのに、すべての公開呼び出し元に traitCollection: パラメーターを追加すると、変更範囲が必要以上に広がり、移行の影響範囲も大きくなります。逆に、各公開呼び出し元が非推奨の状態を直接読み取る場合(ヘルパーがない場合)は、非推奨化は公開呼び出し元に適用します。より低い階層に非推奨化できる箇所はありません。目安: 本来変更する必要がある行を含むメソッドを特定し、そのメソッドを非推奨化してください。非推奨化の連鎖は、対象 API に実際に触れる範囲だけに広げてください。
  16. 対象外置き換えの防止策。 行を編集する前に、次の 2 点を確認してください:(a)その行に現在のタスクの対象となる非推奨 APIが含まれていること、(b)ユーザーが求めている非推奨箇所を編集しており、「似ている」だけの近くの行を編集していないこと。

ワークフロー

Phase 0: シンプルなケースのファストパス

判断ツリーに進む前に、該当箇所がシンプルなケースに当てはまるか確認してください。 UIScreen.main/UIScreen.mainScreen の大部分は、UIView/UIViewController のインスタンスメソッド内で値をその場で使用する単純な置き換えです。これらのケースでは分析は不要です。置き換えて次に進んでください。

元のコード置き換え後
UIView/UIViewController のインスタンスメソッド内で、インラインで使用(保存しない)されている UIScreen.main.scale(Swift)self.traitCollection.displayScale
UIView/UIViewController のインスタンスメソッド内で、インラインで使用(保存しない)されている [UIScreen mainScreen].scale(ObjC)self.traitCollection.displayScale
layoutSubviews、drawRect:、updateConstraints、または viewIsAppearing: 内の UIScreen.main.scaleself.traitCollection.displayScale(登録は不要です。UIKit が特性の変更時にこれらを自動的に呼び出します)

シンプルな置き換えを深読みしないでください。 包含クラスが UIView/UIViewController で、値が ivar、レイヤーのプロパティ、制約、または保存された画像に代入されていない場合は、単に置き換えてください。シンプルなファイルで差分がないままにするのは、最もよくある間違いです。置き換えを適用して次に進んでください。 判断ツリーを使うのは、シンプルなケースに当てはまらない場合(非 view クラス、キャッシュされた値、クラス/static メソッド、特別なユーザー指示)のみです。

Phase 1: 検出

各関連タスクファイルの検出パターンを使って、最新化するパターンを特定します。コードベースに該当する Task Registry 内のすべてのタスクについて検出を実行してください。1 つだけではありません。詳しくは以下のTask Registryを参照してください。

Phase 2: 分析

各該当箇所について、周辺のコンテキストを読み、以下を理解します。

  • クラス階層(UIView/UIViewController のサブクラスか、通常の NSObject か、非 view クラスか)
  • メソッドの種類(インスタンス、static、自由関数、キャッシュされた dispatch_once ヘルパー)
  • ライフサイクルのフェーズ(init、viewDidLoad、viewWillAppear、layoutSubviews)
  • コードの意図(レイアウト、レンダリング、表示スケール、全画面の寸法)

アクティブなタスクの参照ファイルに、タスク固有の項目がこのリストに追加される場合があります。

コンテキストウィンドウを小さく保つため、更新が必要なコードの特定にはサブエージェントを使用してください。

Phase 3: 判断と検証
条件アクション
安全な 1 対 1 の置き換えがある適用してください。 追加のコメントは不要です(// TODO: FIXME、// TODO、// FIXME は追加せず、置き換えのみ行います)。アクティブなタスクの参照ファイルで指定された置き換えを使用してください。
複数の有効な方法がある、またはコードの移動が 10 行を超えるユーザーに確認してください。
安全に置き換える方法がない(極めてまれ)ユーザー向けに明確なタスクを記述した todo を追加してください。差分がないままにしてはいけません。適用できるものがないと結論づける前に、サブエージェントですべてのパターンを再確認してください。

コードを変更する前に、アクティブなタスクの Post-file Checklist に照らして検証するため、サブエージェントを使用してください。

フェーズ 3b:ファイル処理の完全性

対象の非推奨 API が含まれるすべてのファイルを処理してください。 早々に作業を終えたり、ファイルをスキップしたり、作業キューから黙ってファイルを外したりしないでください。フェーズ 1 で特定されたファイルに差分もスキップ理由の説明もない場合、処理の失敗です。

ファイルの明示的な追跡: 処理の開始時に、利用可能なタスク/TODO ツールまたは Markdown ファイルを使って、変更対象のファイルの完全なリストを書き出してください。各ファイルを処理するごとに、完了としてマークしてください。終了前にこのリストと出力を照合してください。差分も明示的なスキップ理由もないファイルがあれば、完了前に必ず対応してください。

コンテキストサイズ: コンテキストサイズが気になる場合は、個々のファイルまたはタスクの処理にサブエージェントを利用してください。

ファイルの黙った脱落の防止: 終了前に、サブエージェントを使って、指定されたファイルのリストと出力を作成したファイルのリストを比較してください。出力に含まれていないファイルがあれば、戻って処理してください。ファイルが黙って脱落する主な原因は次のとおりです。

  • ファイルサイズ: 大きなファイル(1000 行以上)も例外ではありません。同じ方法で処理してください。
  • 複雑さ: プリプロセッサマクロ、複雑なクラス階層、または特殊なコードパターンを含むファイルも変更が必要です。
  • プロジェクトのまとまり: 特定のプロジェクトやディレクトリに属するファイルをすべてスキップしないでください。同じプロジェクトの複数のファイルを脱落させたことに気付いた場合は、体系的な問題を示しているため、調査して修正してください。
  • 曖昧さ: ファイルの修正方法が不明な場合は、ユーザーに確認してください。差分がない状態を黙って出力しないでください。

大規模または複雑なファイル: プリプロセッサの使用頻度が高いファイル(#if/#ifdef のネスト)、1000 行以上のファイル、またはあまり一般的でないパターン(C++ の相互運用、dispatch_once によるキャッシュ、深くネストしたマクロ)も処理対象です。そのようなファイルに対象 API が含まれている場合は、同じ判断フローを適用してください。ファイルを一度に編集するには大きすぎる場合は、非推奨 API の使用箇所を一つずつ処理してください。必要に応じてサブエージェントを利用してください。マクロ展開やプリプロセッサの複雑さのために安全な置き換えを本当に判断できない場合は、ユーザーに確認してください。黙ってスキップしてはいけません。

バッチ処理の徹底: ファイルのリストを処理する際、最初にすべてのファイルを分析してから、差分をまとめて出力しないでください。代わりに、ファイルを一つずつ、または少数(3~5 ファイル)ずつ処理してください。コンテキストを読み、判断し、差分を作成してから、次のバッチに進んでください。これにより、出力制限やコンテキストの枯渇によってリストの後半が黙って脱落するのを防げます。指定されたファイル数より出力したファイル数が少ないことに気付いた場合は、そこで止め、終了前に残りを処理してください。

単純な置き換えで済むはずのファイルに空の差分がある場合は、戻って処理してください。単純なファイルはすぐに処理できるため、決して脱落させてはいけません。

フェーズ 4:実装

有効なタスクの参照ファイルにある実装のゲート、ルール、およびファイル処理後のチェックリストを適用してください。パターン固有の判断フロー、ゲートの質問、検証ルールは、それらが適用される各タスクファイル内に記載されています。検証にはサブエージェントを利用してください。

フェーズ 5:最終検証

ファイル網羅性の監査: サブエージェントを使って、指定された(またはフェーズ 1 で検出した)ファイルのリストと、実際に差分を作成したファイルを比較してください。入力ファイルごとに、空でない差分が必要です。変更がないファイルがあれば、戻って今すぐ処理してください。

有効なタスクの参照ファイルに、タスク固有の検証手順が追加されている場合があります。

タスクレジストリ

開発者の依頼で対象が明示的に限定されていない限り、このレジストリ内のすべてのタスクをコードベースに適用してください。各タスクは独立しており、参照ファイルにそれぞれ固有の検出パターン、判断ツリー、検証ルールがあります。上から順に実行してください。

タスクファイル説明
UIScreen.main のモダナイズuiscreen-task.mdUIScreen.main を状況に応じた API に置き換えます
userInterfaceOrientation のモダナイズorientation-task.mdレイアウト関連の向きの判定をサイズクラスまたはウィンドウの境界に置き換えます
Scene のライフサイクル移行scene-lifecycle-task.mdAppDelegate を SceneDelegate に移行します
セーフエリアのインセットsafe-area-task.mdインセットに対するハードコードされた値をセーフエリア参照に置き換え、既存の参照が非対称なセーフエリアでも機能するようにします

コメント