swift-ui-architect

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Airbnb SwiftUI Best Practices

Airbnb SwiftUI最佳实践

Opinionated, strict architectural enforcement for SwiftUI iOS apps. Contains 43 rules across 8 categories, derived from Airbnb Engineering, Apple WWDC sessions, Clean Architecture patterns, and Advanced iOS App Architecture (raywenderlich). This skill mandates a single, non-negotiable architecture stack.
这是一套针对SwiftUI iOS应用的、具有明确立场的严格架构强制规范。包含8个类别共43条规则,源自Airbnb工程实践、Apple WWDC技术分享、Clean Architecture模式以及《Advanced iOS App Architecture》(raywenderlich)。该规范要求采用一套统一且不可妥协的架构栈。

Mandated Architecture Stack

强制架构栈

┌─────────────────────────────────────────────────────┐
│  Presentation Layer (SwiftUI Views)                 │
│  ├── Views: @Equatable, decomposed, minimal bodies  │
│  ├── ViewModels: @Observable classes via @State      │
│  └── Coordinators: NavigationStack + enum routes     │
├─────────────────────────────────────────────────────┤
│  Domain Layer (Pure Swift)                          │
│  ├── Use Cases / Interactors (stateless, protocol)  │
│  ├── Domain Models (value types, Equatable)         │
│  └── Repository Protocols (abstractions only)       │
├─────────────────────────────────────────────────────┤
│  Data Layer (Implementation)                        │
│  ├── Repository Implementations                     │
│  ├── Network Services                               │
│  └── Persistence (SwiftData / CoreData)             │
└─────────────────────────────────────────────────────┘
Dependency Rule: Arrows point inward only. Views -> Domain <- Data. Domain has zero framework imports.
┌─────────────────────────────────────────────────────┐
│  Presentation Layer (SwiftUI Views)                 │
│  ├── Views: @Equatable, decomposed, minimal bodies  │
│  ├── ViewModels: @Observable classes via @State      │
│  └── Coordinators: NavigationStack + enum routes     │
├─────────────────────────────────────────────────────┤
│  Domain Layer (Pure Swift)                          │
│  ├── Use Cases / Interactors (stateless, protocol)  │
│  ├── Domain Models (value types, Equatable)         │
│  └── Repository Protocols (abstractions only)       │
├─────────────────────────────────────────────────────┤
│  Data Layer (Implementation)                        │
│  ├── Repository Implementations                     │
│  ├── Network Services                               │
│  └── Persistence (SwiftData / CoreData)             │
└─────────────────────────────────────────────────────┘
依赖规则:依赖箭头仅指向内部。视图层 -> 领域层 <- 数据层。领域层不导入任何框架。

When to Apply

适用场景

Reference these guidelines when:
  • Writing any new SwiftUI view, ViewModel, or coordinator
  • Creating or modifying navigation flows
  • Adding data fetching, state management, or dependency injection
  • Reviewing code for architecture compliance or performance
  • Refactoring existing SwiftUI code toward this architecture
在以下场景中参考本规范:
  • 编写任何新的SwiftUI视图、ViewModel或协调器
  • 创建或修改导航流程
  • 添加数据获取、状态管理或依赖注入逻辑
  • 评审代码的架构合规性或性能
  • 将现有SwiftUI代码重构为该架构

Non-Negotiable Constraints (iOS 17+)

不可妥协的约束条件(iOS 17+)

  • @Observable
    everywhere,
    ObservableObject
    /
    @Published
    never
  • NavigationStack
    + coordinator pattern,
    NavigationLink(destination:)
    never
  • @Equatable
    macro on every view,
    AnyView
    never
  • Domain layer has zero SwiftUI/UIKit imports
  • Views never access repositories directly
  • 所有ViewModel均使用
    @Observable
    ,严禁使用
    ObservableObject
    /
    @Published
  • 采用
    NavigationStack
    + 协调器模式,严禁使用
    NavigationLink(destination:)
  • 每个视图都添加
    @Equatable
    宏,严禁使用
    AnyView
  • 领域层不导入任何SwiftUI/UIKit框架
  • 视图严禁直接访问仓库(Repository)

Rule Categories by Priority

按优先级划分的规则类别

PriorityCategoryImpactPrefixRules
1View Identity & DiffingCRITICAL
diff-
6
2State ArchitectureCRITICAL
state-
7
3View CompositionHIGH
view-
6
4Navigation & CoordinationHIGH
nav-
5
5Layer ArchitectureHIGH
layer-
6
6Dependency InjectionMEDIUM-HIGH
di-
4
7List & Collection PerformanceMEDIUM
list-
4
8Async & Data FlowMEDIUM
data-
5
优先级类别影响程度前缀规则数量
1视图标识与差异对比关键
diff-
6
2状态架构关键
state-
7
3视图组合
view-
6
4导航与协调
nav-
5
5分层架构
layer-
6
6依赖注入中高
di-
4
7列表与集合性能
list-
4
8异步与数据流
data-
5

Quick Reference

快速参考

1. View Identity & Diffing (CRITICAL)

1. 视图标识与差异对比(关键)

  • diff-equatable-views
    - Apply @Equatable macro to every SwiftUI view
  • diff-closure-skip
    - Use @SkipEquatable for closure/handler properties
  • diff-reference-types
    - Never store reference types without Equatable conformance
  • diff-identity-stability
    - Use stable O(1) identifiers in ForEach
  • diff-avoid-anyview
    - Never use AnyView — use @ViewBuilder or generics
  • diff-printchanges-debug
    - Use _printChanges() to diagnose unnecessary re-renders
  • diff-equatable-views
    - 为每个SwiftUI视图添加@Equatable宏
  • diff-closure-skip
    - 为闭包/处理器属性使用@SkipEquatable
  • diff-reference-types
    - 严禁存储未遵循Equatable协议的引用类型
  • diff-identity-stability
    - 在ForEach中使用稳定的O(1)标识符
  • diff-avoid-anyview
    - 严禁使用AnyView — 改用@ViewBuilder或泛型
  • diff-printchanges-debug
    - 使用_printChanges()诊断不必要的重渲染

2. State Architecture (CRITICAL)

2. 状态架构(关键)

  • state-observable-class
    - Use @Observable classes for all ViewModels
  • state-ownership
    - @State for owned data, plain property for injected data
  • state-single-source
    - One source of truth per piece of state
  • state-scoped-observation
    - Leverage @Observable property-level tracking
  • state-binding-minimal
    - Pass @Binding only for two-way data flow
  • state-environment-global
    - Use @Environment for app-wide shared dependencies
  • state-no-published
    - Never use @Published or ObservableObject
  • state-observable-class
    - 为所有ViewModel使用@Observable类
  • state-ownership
    - 自有数据使用@State,注入数据使用普通属性
  • state-single-source
    - 每个状态仅有单一数据源
  • state-scoped-observation
    - 利用@Observable的属性级跟踪功能
  • state-binding-minimal
    - 仅在双向数据流场景下传递@Binding
  • state-environment-global
    - 使用@Environment注入全局共享依赖
  • state-no-published
    - 严禁使用@Published或ObservableObject

3. View Composition (HIGH)

3. 视图组合(高)

  • view-body-complexity
    - Maximum 10 nodes in view body
  • view-extract-subviews
    - Extract computed properties/helpers into separate View structs
  • view-no-logic-in-body
    - Zero business logic in body
  • view-minimal-dependencies
    - Pass only needed properties, not entire models
  • view-viewbuilder-composition
    - Use @ViewBuilder for conditional composition
  • view-no-init-sideeffects
    - Never perform work in View init
  • view-body-complexity
    - 视图body中最多包含10个节点
  • view-extract-subviews
    - 将计算属性/辅助逻辑提取为独立的View结构体
  • view-no-logic-in-body
    - 视图body中严禁包含业务逻辑
  • view-minimal-dependencies
    - 仅传递所需属性,而非整个模型
  • view-viewbuilder-composition
    - 使用@ViewBuilder实现条件组合
  • view-no-init-sideeffects
    - 严禁在View的init方法中执行耗时操作

4. Navigation & Coordination (HIGH)

4. 导航与协调(高)

  • nav-coordinator-pattern
    - Every feature has a coordinator owning NavigationStack
  • nav-routes-enum
    - Define all routes as a Hashable enum
  • nav-deeplink-support
    - Coordinators must support URL-based deep linking
  • nav-modal-sheets
    - Present modals via coordinator, not inline
  • nav-no-navigationlink
    - Never use NavigationLink(destination:) — use navigationDestination(for:)
  • nav-coordinator-pattern
    - 每个功能模块都有一个管理NavigationStack的协调器
  • nav-routes-enum
    - 将所有路由定义为遵循Hashable协议的枚举
  • nav-deeplink-support
    - 协调器必须支持基于URL的深度链接
  • nav-modal-sheets
    - 通过协调器展示模态视图,而非内联展示
  • nav-no-navigationlink
    - 严禁使用NavigationLink(destination:) — 改用navigationDestination(for:)

5. Layer Architecture (HIGH)

5. 分层架构(高)

  • layer-dependency-rule
    - Domain layer has zero framework imports
  • layer-usecase-protocol
    - Every use case is a protocol with a single execute method
  • layer-repository-protocol
    - Repository protocols in Domain, implementations in Data
  • layer-model-value-types
    - Domain models are structs, never classes
  • layer-no-view-repository
    - Views never access repositories directly
  • layer-viewmodel-boundary
    - ViewModels expose display-ready state only
  • layer-dependency-rule
    - 领域层不导入任何框架
  • layer-usecase-protocol
    - 每个用例都是一个包含单一execute方法的协议
  • layer-repository-protocol
    - 仓库协议定义在领域层,实现类放在数据层
  • layer-model-value-types
    - 领域模型为结构体,严禁使用类
  • layer-no-view-repository
    - 视图严禁直接访问仓库
  • layer-viewmodel-boundary
    - ViewModel仅对外暴露可直接用于展示的状态

6. Dependency Injection (MEDIUM-HIGH)

6. 依赖注入(中高)

  • di-environment-injection
    - Inject via @Environment with custom EnvironmentKey
  • di-protocol-abstraction
    - All injected dependencies are protocol types
  • di-container-composition
    - Compose dependency container at app root
  • di-mock-testing
    - Every protocol dependency has a mock for testing
  • di-environment-injection
    - 使用带自定义EnvironmentKey的@Environment进行注入
  • di-protocol-abstraction
    - 所有注入的依赖均为协议类型
  • di-container-composition
    - 在应用根节点组合依赖容器
  • di-mock-testing
    - 每个协议依赖都有对应的测试用Mock实现

7. List & Collection Performance (MEDIUM)

7. 列表与集合性能(中)

  • list-constant-viewcount
    - ForEach must produce constant view count per element
  • list-filter-in-model
    - Filter/sort in ViewModel, never inside ForEach
  • list-lazy-stacks
    - Use LazyVStack/LazyHStack for unbounded content
  • list-id-keypath
    - Provide explicit id keyPath — never rely on implicit identity
  • list-constant-viewcount
    - ForEach为每个元素生成的视图数量必须固定
  • list-filter-in-model
    - 在ViewModel中进行过滤/排序,严禁在ForEach内部处理
  • list-lazy-stacks
    - 对无界内容使用LazyVStack/LazyHStack
  • list-id-keypath
    - 提供显式的id键路径 — 严禁依赖隐式标识

8. Async & Data Flow (MEDIUM)

8. 异步与数据流(中)

  • data-task-modifier
    - Use .task {} for async data loading
  • data-async-init
    - Never perform async work in init
  • data-error-loadable
    - Model loading states as enum, not booleans
  • data-combine-avoid
    - Prefer async/await over Combine for new code
  • data-cancellation
    - Use .task automatic cancellation — never manage Tasks manually
  • data-task-modifier
    - 使用.task {}进行异步数据加载
  • data-async-init
    - 严禁在init方法中执行异步操作
  • data-error-loadable
    - 使用枚举对加载状态(含错误)进行建模,严禁使用布尔值
  • data-combine-avoid
    - 新代码优先使用async/await,而非Combine
  • data-cancellation
    - 使用.task的自动取消机制 — 严禁手动管理Task

How to Use

使用方法

Read individual reference files for detailed explanations and code examples:
  • Section definitions - Category structure and impact levels
  • Rule template - Template for adding new rules
阅读单个参考文件获取详细说明和代码示例:
  • 章节定义 - 类别结构和影响级别说明
  • 规则模板 - 添加新规则的模板

Reference Files

参考文件

FileDescription
references/_sections.mdCategory definitions and ordering
assets/templates/_template.mdTemplate for new rules
metadata.jsonVersion and reference information
文件描述
references/_sections.md类别定义与排序说明
assets/templates/_template.md新规则模板
metadata.json版本与参考信息