iOS開発とAIコーディングツールの相性は、正直あまり語られていません。
Claude Codeはターミナルで動きます。XcodeはGUIファーストです。この溝は実在します。「iOSでもAIコーディング使えます!」という記事の多くが、不都合な部分を飛ばしているのが現状です。
このガイドは飛ばしません。Claude CodeがSwift/iOSプロジェクトで本当に役立つ場面、役立たない場面、そして役立つ部分を最大化するためのCLAUDE.mdの書き方を解説します。
Claude Code + iOS:何が得意で、何が苦手か
最初に正直なところから入ります。
Claude Codeが効果的な場面:
- Swift Package Manager(SPM)プロジェクト — 完全なターミナルワークフロー
- ViewModel・Service・Repositoryなどビジネスロジック層のコード
- 既存モデル・サービスコードからのXCTestユニットテスト生成
- アーキテクチャルールに基づくSwiftファイルのリファクタリング
- Swift 6の並行処理パターンのコードベース全体への適用
- SPMパッケージの
swift build・swift test
Claude Codeが苦手な場面:
- XcodeのGUI操作 —
.xcworkspaceファイルを意味ある形では扱えない - SwiftUIプレビュー — XcodeのCanvasが必要で、ターミナルからはアクセス不可
- 実機デプロイ — コード署名とプロビジョニングプロファイルはXcodeを通じてのみ設定可能
- シミュレーターのGUI操作 —
xcrun simctlでシミュレーターを起動できても、ボタンタップや表示確認はできない .xcodeprojへのファイル追加 — Xcodeターゲットへの新規ファイル登録はXcodeのGUIまたはxcodegenが必要
実用的な結論:ロジックとテストはClaude Code、UIとデプロイはXcodeという分業が現実的です。
XcodeプロジェクトのCLAUDE.md完全テンプレート
プロジェクト名・Swiftバージョン・アーキテクチャに合わせて調整してください。
# iOSアプリ: [AppName]
## ビルド・テストコマンド
- ビルド(シミュレーター): `xcodebuild -project [App].xcodeproj -scheme [App] -sdk iphonesimulator -configuration Debug build`
- ビルド(SPMパッケージ): `swift build`
- テスト: `xcodebuild test -project [App].xcodeproj -scheme [App] -destination 'platform=iOS Simulator,name=iPhone 16'`
- Lint: `swiftlint --strict`
- フォーマット: `swiftformat .`
- SPM更新: `swift package update`
## Swiftバージョンとターゲット
- Swiftバージョン: 6.0(Package.swiftまたはプロジェクト設定で確認)
- iOSデプロイターゲット: 17.0以上
- Xcodeバージョン: 16.x
## 言語規約
- Swift並行処理(async/await、Actor)を使う — 新規コードでのDispatchQueue使用禁止
- 新規Viewは必ずSwiftUI — UIKitはレガシー互換層のみ
- MVVMアーキテクチャ: View → ViewModel(ObservableObject)→ Service → Repository
- 命名: 型はPascalCase、変数・関数はcamelCase
- エラーハンドリング: Swift 6のtyped throwsまたはResult<T, Error>
- 強制アンラップ(`!`)禁止 — guard let / if let / nil合体演算子を使う
## アーキテクチャルール
- ViewModelにSwiftUIをimport禁止(ビジネスロジックのみ)
- ServiceはProtocol経由で注入する
- Viewファイルにビジネスロジックを書かない
- ファイル1つにつき1型(1 type per file)
- RepositoryはServiceからデータソースを抽象化する
## テスト
- ViewModel・Service・RepositoryのユニットテストはXCTest
- UIテストはXCUITest — ユニットテストとは別ターゲットで管理
- Protocolでモック: ServiceProtocolを定義し、MockServiceを作成してテスト注入
- MainActor対応: UIを更新するViewModelのメソッドテストは`@MainActor`コンテキストで実行
- 新規public関数にはユニットテストを最低1件用意する
## 依存関係管理
- 新規依存はSwift Package Managerを優先
- CocoaPodsは既存サードパーティSDKで必要な場合のみ(新規Pod追加は避ける)
- Package.swiftのコメントに各依存を採用した理由を記載する
- 依存追加は相談してから
## SwiftUIパターン
- `@State`: ローカルUI状態のみ(ビジネスデータに使わない)
- `@StateObject`: Viewが所有するViewModel(Viewが生成する場合)
- `@ObservedObject`: 外部から渡されるViewModel(親が生成する場合)
- `@EnvironmentObject`: アプリルートから`.environmentObject()`で注入するグローバル状態
- View bodyが50行を超えたらサブビューに分割する
- Previewは同ファイルに記述し、モックデータを使う
## Swift並行処理ルール
- 非同期処理はすべてasync/await — 新規コードにコールバック不使用
- UIを更新するViewModelクラスには`@MainActor`アノテーション必須
- syncからasyncのブリッジには`Task { }`を使う — `DispatchQueue.main.async`は使わない
- 複数タスクからアクセスする共有可変状態はActorで保護する
- 並列処理は`async let`を優先 — `Task.detached`は最終手段
## メモリ管理
- 循環参照防止 — selfをキャプチャするクロージャには`[weak self]`を使う
- ServiceはViewControllerやViewへの強参照を持たない
- 必要でない限り`@objc`ラッパーを使わない
## このプロジェクトでのClaude Code制限事項
- Xcodeプレビューは実行不可 — UI変更は必ずXcodeで目視確認
- 実機への署名・デプロイは不可
- .xcodeprojのターゲットメンバーシップ変更不可 — Xcodeで手動追加する
- シミュレーター操作は`xcrun simctl`のCLIコマンドのみ
- 得意な作業: ロジックコード、SPMパッケージ、ユニットテスト、ファイル単位のSwift変更
ビルドコマンド:xcodebuild と swift build
CLAUDE.mdのビルドコマンドセクションは見た目以上に重要です。Claude Codeはこれらのコマンドを実行して、変更がコンパイルできることを確認してからタスク完了と判断します。
SPM専用パッケージの場合(最もシンプル):
swift build
swift test
swift test --filter ViewModelTests # テストクラスを絞り込む
Xcodeプロジェクトの場合:
# 利用可能なスキームの確認
xcodebuild -list -project MyApp.xcodeproj
# シミュレーター向けビルド
xcodebuild \
-project MyApp.xcodeproj \
-scheme MyApp \
-sdk iphonesimulator \
-configuration Debug \
build
# テスト実行
xcodebuild test \
-project MyApp.xcodeproj \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 16,OS=18.0'
CLAUDE.mdにはプロジェクト名・スキーム名を埋めた状態のコマンドを書いてください。Claude Codeはそのまま使います。
SwiftUI property wrapperのルール
@StateObjectと@ObservedObjectの混同は、SwiftUIで最もよく見るバグの一つです。ViewがViewModelを自分で生成するのに@ObservedObjectを使うと、再レンダリングのたびにViewModelが作り直されます。
CLAUDE.mdに明示することで防げます:
## SwiftUI property wrapperルール
- `@State`: UI用プリミティブ値(Bool、String、Int)— ビジネスデータに使わない
- `@StateObject`: このViewが生成・所有するViewModel
- `@ObservedObject`: 親Viewから渡されるViewModel — Viewが自分でinstantiateしない場合のみ
- `@EnvironmentObject`: `.environmentObject()`でルートから注入したアプリ全体の状態
- `@Binding`: 親の@Stateへの双方向バインディング
- 要注意: ViewがViewModel自身を生成するなら必ず@StateObject — @ObservedObjectだと再レンダリングで状態消失
Swift 6並行処理ルール(async/await、Actor)
Swift 6は並行処理のチェックが厳格です。Swift 5では警告だったものがコンパイルエラーになります。CLAUDE.mdにルールを書かないと、Claude Codeがコンパイルできないコードを生成します。
## 並行処理ルール(Swift 6)
- ViewModelクラスには`@MainActor`必須(@PublishedプロパティはUIから観測される)
- すべての非同期呼び出しに`await`を付ける — コールバック・DispatchQueue禁止
- 並列処理: `async let a = fetchA(); async let b = fetchB(); let (x, y) = await (a, b)`
- 共有可変状態: serial DispatchQueueではなくActorを定義する
- アクター境界を越えて渡す型はSendable準拠が必要
ActorはDispatchQueueベースのパターンからの移行で特に重要です。古いコードベースを扱う場合、CLAUDE.mdに「DispatchQueueは使わない、Actorに置き換える」と明示すれば、Claude Codeは新規コードで正しいパターンを使います。
テスト戦略:XCTest + Protocolモック
Claude CodeはXCTestの雛形生成が得意ですが、プロジェクトのモック戦略を知っている必要があります。
## テストパターン
- すべてのServiceにProtocolを定義: NetworkServiceProtocol、DatabaseServiceProtocol
- テストはモック実装を注入: MockNetworkService: NetworkServiceProtocol
- ViewModelのinitはConcreteクラスではなくProtocolを受け取る
- テストファイルの場所: Tests/<FeatureName>Tests/<Feature>ViewModelTests.swift
- フィクスチャデータ: Tests/Fixtures/ にJSON または Swiftのstruct
- テスト対象ViewModelが@MainActor隔離の場合、テストメソッドにも@MainActorを付ける
最後の@MainActorの記述は特に重要です。これがないとClaude Codeは@MainActor隔離されたメソッドを非隔離コンテキストから呼び出すテストを生成し、Swift 6のコンパイルエラーになります。
SwiftLint + SwiftFormat 統合
SwiftLintがプロジェクトに入っているなら、CLAUDE.mdで場所を明示することで、コード生成後に自動Lintさせられます。
## LintとFormat
- Lint: `swiftlint --strict`(設定: プロジェクトルートの`.swiftlint.yml`)
- Format: `swiftformat .`(設定: プロジェクトルートの`.swiftformat`)
- Swiftファイル変更後は必ずLint実行
- SwiftLint違反はPRマージをブロック — 警告も含めてすべて修正
- 無効化ルール(プロジェクト固有): line_length(140文字まで許可)、file_length
ファイル編集のたびに自動でSwiftLintを走らせるHookの設定:
{
"PostToolUse": [
{
"matcher": "Edit",
"hooks": [
{
"type": "command",
"command": "swiftlint --strict"
}
]
}
]
}
.claude/settings.jsonに配置すると、ファイル編集のたびにSwiftLintが自動実行されます。
SPM専用プロジェクト:Claude Codeとの最良の組み合わせ
Swiftパッケージ(ライブラリ、CLIツール、Xcodeプロジェクトからimportされるフレームワーク)を作るなら、Claude Codeとの相性は最高です。Xcodeなしで完全なターミナルワークフローが成立します。
# [PackageName] Swift Package
## ビルド・テスト
- Build: `swift build`
- Test: `swift test`
- 詳細出力: `swift test --verbose`
- Xcodeプロジェクト生成(任意): `swift package generate-xcodeproj`
- クリーン: `swift package clean`
## Swiftルール
- Swift 6.0 strict concurrency有効(Package.swiftで`-strict-concurrency=complete`)
- すべてのpublic APIにDocCコメント(`///`)
- 強制アンラップ(`!`)禁止 — guard let / if let / throwを使う
- アクター境界を越える型はSendable準拠
- コアロジックにFoundation importを最小化
マルチツールチーム向けAGENTS.md版
チームでClaude Code以外のAIツール(Cursor、Copilotなど)も使う場合、プロジェクトルートのAGENTS.mdがすべてのツールに読まれる共通設定になります。
# [AppName] — AI エージェント設定
## 概要
Swift 6・SwiftUI・MVVMアーキテクチャのiOSアプリ。Swift Package Manager使用。
## ビルド・テスト
- Build: `xcodebuild -project App.xcodeproj -scheme App -sdk iphonesimulator build`
- Test: `xcodebuild test -project App.xcodeproj -scheme App -destination 'platform=iOS Simulator,name=iPhone 16'`
- SPMのみ: `swift build && swift test`
## アーキテクチャ
- MVVM: Views → ViewModels (@MainActor, ObservableObject) → Services(Protocol)→ Repositories
- Viewファイルにビジネスロジック禁止
- ViewModelファイルにSwiftUI import禁止
## Swift規約
- async/await必須、新規コードにDispatchQueue禁止
- 共有可変状態はActorで保護
- Protocol注入でテスタビリティを確保
- 1ファイル1型
## Lint
- Swiftファイル変更後`swiftlint --strict`を実行
- 警告ゼロポリシー
## AIツールの制限事項(共通)
- SwiftUIプレビューは実行不可 — Xcodeで目視確認
- .xcodeprojのターゲットメンバーシップ変更不可 — xcodegen使用か手動追加
Claude固有の設定(会話スタイル、コミットメッセージの形式、確認の取り方など)はCLAUDE.mdに分けて書くのがおすすめです。
Swiftと iOS向けのCLAUDE.mdパターンはルールギャラリーでも公開しています。マルチモジュール構成やDocCドキュメント付きSwiftパッケージのテンプレートもあります。
よくある質問
Claude CodeはCocoaPodsプロジェクトで動きますか?
動きます。ただし制限があります。Claude CodeはCocoaPodsプロジェクト内のSwiftファイルを編集でき、xcodebuildコマンドを実行できます。ただし、pod installの信頼性は環境依存が高く、Podfileを適切に編集するには既存のpodバージョンとiOSターゲットの知識が必要です。pod更新コマンドはCLAUDE.mdに記載し、手動ステップとして扱うのが無難です。
Swift 6の並行処理エラーをClaude Codeは理解できますか?
はい、これはClaude Codeの強みの一つです。swift buildでSwift 6の並行処理エラーが出た場合、エラーメッセージを読んで適切な修正(@MainActor追加、Sendable準拠、非同期呼び出しの再構成など)を提案するのが得意です。CLAUDE.mdに並行処理ルールを書いておけば、そもそもエラーが発生するコードを生成しなくなります。
SwiftDataプロジェクトでも使えますか?
SwiftData(Appleの新しい永続化フレームワーク)はマクロを使いますが、Claude Codeはコード構文として扱えます。CLAUDE.mdに書くべき重要な点は、ModelContainerをどこで定義するか、ModelContextをどう注入するかというDI設計です。ネットワークサービスの注入ルールと同じ考え方が適用されます。
Objective-Cファイルが混在するプロジェクトはどうですか?
Claude CodeはObjective-Cファイルの読み書きはできますが、Swiftと比べると品質が落ちます。Swift/ObjC混在プロジェクトの場合は、「Objective-Cファイルはレガシーで、新規ロジックをここに追加しない。新規作業はSwiftで行う」とCLAUDE.mdに明示することをおすすめします。