本文へ移動
cccskills
無料GitHub で公開

swiftui-patterns

SwiftUIアーキテクチャパターン、@Observableによる状態管理、ビュー合成、ナビゲーション、パフォーマンス最適化、モダンなiOS/macOS UIのベストプラクティス。

インストール方法を見る

含まれるファイル(1)

  • SKILL.md7.7 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

SwiftUIパターン

Appleプラットフォーム上で宣言的かつ高性能なUIを構築するためのモダンなSwiftUIパターン。Observationフレームワーク、ビュー合成、型安全なナビゲーション、パフォーマンス最適化をカバー。

アクティベーション条件

  • SwiftUIビューの構築と状態管理(@State、@Observable、@Binding)
  • NavigationStackによるナビゲーションフローの設計
  • ビューモデルとデータフローの構造化
  • リストや複雑なレイアウトのレンダリングパフォーマンス最適化
  • SwiftUIにおけるEnvironment値と依存性注入の操作

状態管理

プロパティラッパーの選択

適合する最もシンプルなラッパーを選択:

ラッパーユースケース
@Stateビューローカルの値型(トグル、フォームフィールド、シート表示)
@Binding親の@Stateへの双方向参照
@Observableクラス + @State複数プロパティを持つ所有モデル
@Observableクラス(ラッパーなし)親から渡される読み取り専用参照
@Bindable@Observableプロパティへの双方向バインディング
@Environment.environment()で注入される共有依存関係

@Observable ViewModel

@Observableを使用(ObservableObjectではなく)— プロパティレベルの変更を追跡するため、SwiftUIは変更されたプロパティを読み取るビューのみを再レンダリング:

@Observable
final class ItemListViewModel {
    private(set) var items: [Item] = []
    private(set) var isLoading = false
    var searchText = ""

    private let repository: any ItemRepository

    init(repository: any ItemRepository = DefaultItemRepository()) {
        self.repository = repository
    }

    func load() async {
        isLoading = true
        defer { isLoading = false }
        items = (try? await repository.fetchAll()) ?? []
    }
}

ViewModelを使用するビュー

struct ItemListView: View {
    @State private var viewModel: ItemListViewModel

    init(viewModel: ItemListViewModel = ItemListViewModel()) {
        _viewModel = State(initialValue: viewModel)
    }

    var body: some View {
        List(viewModel.items) { item in
            ItemRow(item: item)
        }
        .searchable(text: $viewModel.searchText)
        .overlay { if viewModel.isLoading { ProgressView() } }
        .task { await viewModel.load() }
    }
}

Environmentインジェクション

@EnvironmentObjectを@Environmentに置き換え:

// 注入
ContentView()
    .environment(authManager)

// 使用
struct ProfileView: View {
    @Environment(AuthManager.self) private var auth

    var body: some View {
        Text(auth.currentUser?.name ?? "Guest")
    }
}

ビュー合成

無効化を制限するためにサブビューを抽出

ビューを小さく焦点を絞った構造体に分割。状態が変更されると、その状態を読み取るサブビューのみが再レンダリング:

struct OrderView: View {
    @State private var viewModel = OrderViewModel()

    var body: some View {
        VStack {
            OrderHeader(title: viewModel.title)
            OrderItemList(items: viewModel.items)
            OrderTotal(total: viewModel.total)
        }
    }
}

再利用可能なスタイリングのためのViewModifier

struct CardModifier: ViewModifier {
    func body(content: Content) -> some View {
        content
            .padding()
            .background(.regularMaterial)
            .clipShape(RoundedRectangle(cornerRadius: 12))
    }
}

extension View {
    func cardStyle() -> some View {
        modifier(CardModifier())
    }
}

ナビゲーション

型安全なNavigationStack

プログラム的で型安全なルーティングのためにNavigationStackとNavigationPathを使用:

@Observable
final class Router {
    var path = NavigationPath()

    func navigate(to destination: Destination) {
        path.append(destination)
    }

    func popToRoot() {
        path = NavigationPath()
    }
}

enum Destination: Hashable {
    case detail(Item.ID)
    case settings
    case profile(User.ID)
}

struct RootView: View {
    @State private var router = Router()

    var body: some View {
        NavigationStack(path: $router.path) {
            HomeView()
                .navigationDestination(for: Destination.self) { dest in
                    switch dest {
                    case .detail(let id): ItemDetailView(itemID: id)
                    case .settings: SettingsView()
                    case .profile(let id): ProfileView(userID: id)
                    }
                }
        }
        .environment(router)
    }
}

パフォーマンス

大規模コレクションにはLazyコンテナを使用

LazyVStackとLazyHStackは表示時にのみビューを作成:

ScrollView {
    LazyVStack(spacing: 8) {
        ForEach(items) { item in
            ItemRow(item: item)
        }
    }
}

安定した識別子

ForEachでは常に安定したユニークなIDを使用 — 配列インデックスの使用を避ける:

// Identifiable適合または明示的なidを使用
ForEach(items, id: \.stableID) { item in
    ItemRow(item: item)
}

body内での高コスト処理を避ける

  • body内でI/O、ネットワーク呼び出し、重い計算を決して行わない
  • 非同期作業には.task {}を使用 — ビューが消えると自動的にキャンセル
  • スクロールビュー内での.sensoryFeedback()や.geometryGroup()の使用は控えめに
  • リスト内の.shadow()、.blur()、.mask()を最小限に — オフスクリーンレンダリングを発生させる

Equatable適合

高コストなbodyを持つビューでは、不要な再レンダリングをスキップするためにEquatableに適合:

struct ExpensiveChartView: View, Equatable {
    let dataPoints: [DataPoint] // DataPointはEquatableに適合必要

    static func == (lhs: Self, rhs: Self) -> Bool {
        lhs.dataPoints == rhs.dataPoints
    }

    var body: some View {
        // 複雑なチャートレンダリング
    }
}

プレビュー

高速なイテレーションのためにインラインモックデータと#Previewマクロを使用:

#Preview("Empty state") {
    ItemListView(viewModel: ItemListViewModel(repository: EmptyMockRepository()))
}

#Preview("Loaded") {
    ItemListView(viewModel: ItemListViewModel(repository: PopulatedMockRepository()))
}

避けるべきアンチパターン

  • 新しいコードでObservableObject / @Published / @StateObject / @EnvironmentObjectを使用 — @Observableに移行
  • bodyやinitに直接非同期処理を入れる — .task {}または明示的なロードメソッドを使用
  • データを所有しない子ビュー内で@Stateとしてビューモデルを作成 — 代わりに親から渡す
  • AnyView型消去を使用 — 条件付きビューには@ViewBuilderやGroupを推奨
  • アクターとの間でデータを渡す際のSendable要件を無視

参考

スキルswift-actor-persistenceでアクターベースの永続化パターンを参照。 スキルswift-protocol-di-testingでプロトコルベースのDIとSwift Testingによるテストを参照。

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

agent-eval

無料日本語概要

コーディングエージェント(Claude Code、Aider、Codexなど)のカスタムタスクによる直接比較。合格率、コスト、時間、一貫性メトリクスを測定

hage-oyaji/everything-claude-code-jp-local32026年3月29日 更新

agent-harness-construction

無料日本語概要

AIエージェントのアクションスペース、ツール定義、オブザベーションフォーマットを設計・最適化し、タスク完了率を向上させる

hage-oyaji/everything-claude-code-jp-local32026年3月29日 更新

agentic-engineering

無料日本語概要

評価ファーストの実行、分解、コスト考慮型モデルルーティングによるエージェンティックエンジニアとしての運用

hage-oyaji/everything-claude-code-jp-local32026年3月29日 更新

ai-first-engineering

無料日本語概要

AIエージェントが実装出力の大部分を生成するチームのためのエンジニアリング運用モデル

hage-oyaji/everything-claude-code-jp-local32026年3月29日 更新

ai-regression-testing

無料日本語概要

AI支援開発のためのリグレッションテスト戦略。データベース依存なしのサンドボックスモードAPIテスト、自動バグチェックワークフロー、同一モデルがコードの作成とレビューを行う際のAIの盲点を検出するパターン。

hage-oyaji/everything-claude-code-jp-local32026年3月29日 更新

android-clean-architecture

無料日本語概要

AndroidおよびKotlin Multiplatformプロジェクトのためのクリーンアーキテクチャパターン — モジュール構成、依存関係ルール、UseCase、Repository、データレイヤーパターン

hage-oyaji/everything-claude-code-jp-local32026年3月29日 更新

hage-oyaji のスキルをすべて見る

このスキルの問題を報告する