swiftui-patterns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SwiftUI Patterns (iOS 17+)

SwiftUI Patterns (iOS 17+)

SwiftUI 17+ removes ObservableObject boilerplate with @Observable, simplifies environment injection with @Environment, and introduces task-based async patterns. The core principle: use Apple's modern APIs instead of reactive libraries.
SwiftUI 17+ 借助@Observable移除了ObservableObject的冗余代码,通过@Environment简化了环境注入,并引入了基于任务的异步模式。核心原则:使用Apple的现代API而非响应式库。

Overview

概述

Quick Reference

快速参考

NeedUse (iOS 17+)NOT
Observable model
@Observable
ObservableObject
Published propertyRegular property
@Published
Own state
@State
@StateObject
Passed model (binding)
@Bindable
@ObservedObject
Environment injection
environment(_:)
environmentObject(_:)
Environment access
@Environment(Type.self)
@EnvironmentObject
Async on appear
.task { }
.onAppear { Task {} }
Value change
onChange(of:initial:_:)
onChange(of:perform:)
需求iOS 17+ 推荐用法不推荐用法
可观察模型
@Observable
ObservableObject
可发布属性常规属性
@Published
自有状态
@State
@StateObject
传递的模型(绑定)
@Bindable
@ObservedObject
环境注入
environment(_:)
environmentObject(_:)
环境访问
@Environment(Type.self)
@EnvironmentObject
出现时执行异步操作
.task { }
.onAppear { Task {} }
值变更
onChange(of:initial:_:)
onChange(of:perform:)

Core Workflow

核心工作流程

  1. Use
    @Observable
    for model classes (no @Published needed)
  2. Use
    @State
    for view-owned models,
    @Bindable
    for passed models
  3. Use
    .task { }
    for async work (auto-cancels on disappear)
  4. Use
    NavigationStack
    with
    NavigationPath
    for programmatic navigation
  5. Apply
    .accessibilityLabel()
    and
    .accessibilityHint()
    to interactive elements
  1. 为模型类使用
    @Observable
    (无需@Published)
  2. 视图自有模型使用
    @State
    ,传递的模型使用
    @Bindable
  3. 异步工作使用
    .task { }
    (在视图消失时自动取消)
  4. 结合
    NavigationStack
    与
    NavigationPath
    实现程序化导航
  5. 为交互元素添加
    .accessibilityLabel()
    和
    .accessibilityHint()

Reference Loading Guide

参考资料加载指南

ALWAYS load reference files if there is even a small chance the content may be required. It's better to have the context than to miss a pattern or make a mistake.
ReferenceLoad When
ObservableCreating new
@Observable
model classes
State ManagementDeciding between
@State
,
@Bindable
,
@Environment
EnvironmentInjecting dependencies into view hierarchy
View ModifiersUsing
onChange
,
task
, or iOS 17+ modifiers
Migration GuideUpdating iOS 16 code to iOS 17+
MVVM ObservableSetting up view model architecture
NavigationProgrammatic or deep-link navigation
PerformanceLists with 100+ items or excessive re-renders
UIKit InteropWrapping UIKit components (WKWebView, PHPicker)
AccessibilityVoiceOver, Dynamic Type, accessibility actions
Async PatternsLoading states, refresh, background tasks
CompositionReusable view modifiers or complex conditional UI
只要有哪怕一点点可能需要用到相关内容,就务必加载参考文件。拥有上下文总比遗漏模式或犯错要好。
参考资料加载场景
Observable创建新的
@Observable
模型类时
State Management决定使用
@State
、
@Bindable
还是
@Environment
时
Environment向视图层级注入依赖时
View Modifiers使用
onChange
、
task
或iOS 17+修饰符时
Migration Guide将iOS 16代码升级到iOS 17+时
MVVM Observable搭建视图模型架构时
Navigation实现程序化或深度链接导航时
Performance处理包含100+条目的列表或过度重渲染问题时
UIKit Interop封装UIKit组件(WKWebView、PHPicker)时
Accessibility处理VoiceOver、动态类型、无障碍操作时
Async Patterns实现加载状态、刷新、后台任务时
Composition实现可复用视图修饰符或复杂条件UI时

Common Mistakes

常见错误

  1. Over-using
    @Bindable
    for passed models
    — Creating
    @Bindable
    for every property causes unnecessary view reloads. Use
    @Bindable
    only for mutable model properties that need two-way binding. Read-only computed properties should use regular properties.
  2. State placement errors — Putting model state in the view instead of a dedicated
    @Observable
    model causes view logic to become tangled. Always separate model and view concerns.
  3. NavigationPath state corruption — Mutating
    NavigationPath
    incorrectly can leave it in inconsistent state. Use
    navigationDestination(for:destination:)
    with proper state management to avoid path corruption.
  4. Missing
    .task
    cancellation
    —
    .task
    handles cancellation on disappear automatically, but nested Tasks don't. Complex async flows need explicit cancellation tracking to avoid zombie tasks.
  5. Ignoring environment invalidation — Changing environment values at parent doesn't invalidate child views automatically. Use
    @Environment
    consistently and understand when re-renders happen based on observation.
  6. UIKit interop memory leaks —
    UIViewRepresentable
    and
    UIViewControllerRepresentable
    can leak if delegate cycles aren't broken. Weak references and explicit cleanup are required.
  1. 过度为传递的模型使用
    @Bindable
    —— 为每个属性创建
    @Bindable
    会导致不必要的视图重载。仅对需要双向绑定的可变模型属性使用
    @Bindable
    。只读计算属性应使用常规属性。
  2. 状态放置错误 —— 将模型状态放在视图中而非专用的
    @Observable
    模型中会导致视图逻辑混乱。务必分离模型和视图关注点。
  3. NavigationPath状态损坏 —— 不正确地修改
    NavigationPath
    会使其处于不一致状态。使用
    navigationDestination(for:destination:)
    并配合正确的状态管理,以避免路径损坏。
  4. 遗漏
    .task
    取消处理
    ——
    .task
    会在视图消失时自动处理取消,但嵌套的Task不会。复杂的异步流程需要显式的取消跟踪,以避免僵尸任务。
  5. 忽略环境失效 —— 在父视图中更改环境值不会自动使子视图失效。持续使用
    @Environment
    ,并理解基于观察的重渲染触发时机。
  6. UIKit互操作内存泄漏 —— 如果不打破委托循环,
    UIViewRepresentable
    和
    UIViewControllerRepresentable
    可能会发生内存泄漏。需要使用弱引用和显式清理。