Communitygithub.com

SwiftUI 模式

SwiftUI 架构模式、基于 @Observable 的状态管理、视图组合、导航、性能优化以及现代 iOS/macOS UI 最佳实践。在构建或审查 SwiftUI 视图、@Observable 状态、导航或渲染性能时使用。

SwiftUI 模式 是什么?

这个技能提供了在 Apple 平台 (iOS, macOS 等) 上使用现代 SwiftUI 构建声明式、高性能用户界面的全面指南。它涵盖了如何使用 Observation 框架进行状态管理,包括 @State、@Binding、@Observable 和 @Bindable 等属性包装器的选择和使用场景。该技能深入讲解了视图组合策略,通过提取细粒度子视图和创建可复用的 ViewModifier 来优化渲染性能,并介绍了如何使用 NavigationStack 和 NavigationPath 进行类型安全的编程式导航。此外,它还提供了性能优化技巧,如使用 LazyVStack、稳定标识符、避免在 body 中进行昂贵操作以及实现 Equatable 协议来避免不必要的重绘。该技能适用于 Claude Code、Cursor 以及其他支持 SwiftUI 开发的 AI 编码工具,旨在帮助开发者遵循最佳实践,避免常见反模式,构建可维护且高效的 SwiftUI 应用。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/swiftui-patterns

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

SwiftUI 模式 是做什么的?

适用于 Apple 平台的现代 SwiftUI 模式,用于构建声明式、高性能的用户界面。涵盖 Observation 框架、视图组合、类型安全导航和性能优化。

何时激活

  • 构建 SwiftUI 视图和管理状态 (@State, @Observable, @Binding)
  • 使用 NavigationStack 设计导航流程
  • 构建视图模型和数据流
  • 优化列表和复杂布局的渲染性能
  • 在 SwiftUI 中处理环境值和依赖注入

状态管理

属性包装器选择

选择最适合的简单包装器:

包装器使用场景
@State视图本地的值类型(开关、表单字段、Sheet 呈现)
@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:

// 注入
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

使用带有 NavigationPath 的 NavigationStack 进行编程式、类型安全的路由:

@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 协议一致性

对于包含昂贵 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("空状态") {
    ItemListView(viewModel: ItemListViewModel(repository: EmptyMockRepository()))
}

#Preview("已加载") {
    ItemListView(viewModel: ItemListViewModel(repository: PopulatedMockRepository()))
}

应避免的反模式

  • 在新代码中使用 ObservableObject / @Published / @StateObject / @EnvironmentObject —— 迁移到 @Observable
  • 将异步工作直接放在 body 或 init 中 —— 使用 .task {} 或显式加载方法
  • 在不拥有数据的子视图中将 ViewModel 创建为 @State —— 改成从父视图传递
  • 使用 AnyView 类型擦除 —— 对于条件视图,优先使用 @ViewBuilder 或 Group
  • 在向/从 actor 传递数据时忽略 Sendable 要求

参考

有关基于 actor 的持久化模式,请参考技能:swift-actor-persistence 有关基于协议的依赖注入和 Swift Testing 测试,请参考技能:swift-protocol-di-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/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

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.

相关技能