Communitygithub.com

swiftui-patterns

SwiftUIアーキテクチャパターン、@Observableによる状態管理、ビュー構成、ナビゲーション、パフォーマンス最適化、そしてモダンなiOS/macOS UIのベストプラクティス。SwiftUIビュー、@Observable状態、ナビゲーション、レンダリングパフォーマンスの構築またはレビュー時に使用します。

swiftui-patterns とは?

このスキルは、Appleプラットフォーム向けの宣言的で高性能なユーザーインターフェースを構築するためのモダンなSwiftUIパターンを提供します。Observationフレームワーク、ビュー合成、型安全なナビゲーション、パフォーマンス最適化をカバーしており、開発者がSwiftUIアプリケーションをより効率的に設計・実装できるように支援します。主にClaude CodeなどのAIエージェント上で動作し、SwiftUIの状態管理においては、従来のObservableObjectではなく@Observableマクロを使用し、プロパティレベルの変更追跡によって不要な再レンダリングを防ぎます。また、NavigationStackを用いた型安全なルーティング、遅延コンテナ(LazyVStack/LazyHStack)による大規模コレクションのパフォーマンス最適化、Equatable準拠によるビューの無駄な再描画回避など、実践的なテクニックが体系的にまとめられています。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/swiftui-patterns

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

SwiftUI Patterns

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

アクティブ化するタイミング

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

状態管理

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

最もシンプルなラッパーを選択します:

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

@Observable ViewModel

ObservableObjectではなく@Observableを使用します。プロパティレベルの変更を追跡するため、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() }
    }
}

環境注入

@EnvironmentObjectを@Environmentに置き換えます:

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

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

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

ビュー構成

サブビューを抽出して無効化を制限

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

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)
    }
}

パフォーマンス

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

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準拠

本体が高負荷なビューの場合、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("空の状態") {
    ItemListView(viewModel: ItemListViewModel(repository: EmptyMockRepository()))
}

#Preview("データ読み込み済み") {
    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を使用したテスト)

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

関連スキル