claude-code/claude-zh/skills/swiftui-patterns/SKILL.md

71 lines
2.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: swiftui-patterns
description: SwiftUI 架構模式,涵蓋使用 @Observable 進行狀態管理、視圖組合、導航、效能優化以及現代 iOS/macOS UI 最佳實踐。
---
# SwiftUI 開發模式 (SwiftUI Patterns)
用於 Apple 平台建構聲明式、高性能用戶介面的現代 SwiftUI 模式。內容涵蓋 Observation 框架、視圖組合 (View Composition)、類型安全導航以及效能優化。
## 何時啟用
- 編寫 SwiftUI View 並管理狀態 (`@State`, `@Observable`, `@Binding`)。
- 使用 `NavigationStack` 設計導航流程。
- 規劃 View Model 架構與數據流。
- 優化長列表 (Lists) 或複雜佈局的渲染效能。
- 在 SwiftUI 中使用環境值 (Environment Values) 與依賴注入。
## 狀態管理 (State Management)
### 屬性包裝器 (Property Wrappers) 選用指南
| 包裝器 | 適用場景 |
|---------|----------|
| `@State` | View 本地數據開關狀態、表單欄位、Sheet 顯示開關)。 |
| `@Binding` | 對父視圖 `@State` 的雙向引用。 |
| `@Observable` | 現代化的數據模型ViewModel僅在屬性變動時更新相關視圖。 |
| `@Bindable` | 實現對 `@Observable` 屬性的雙向綁定。 |
| `@Environment` | 跨層級共享的依賴項注入。 |
### 現代化 ViewModel (@Observable)
優先使用 `@Observable` 巨集而非舊有的 `ObservableObject`
```swift
@Observable
final class ItemListViewModel {
private(set) var items: [Item] = []
private(set) var isLoading = false
var searchText = ""
func load() async {
isLoading = true
defer { isLoading = false }
// 執行非同步載入邏輯
}
}
```
## 視圖組合 (View Composition)
- **精簡化視圖結構**:將大型視圖拆解為多個小型 Struct。當狀態變動時SwiftUI 僅會重新渲染讀取該狀態的子視圖。
- **自定義 ViewModifier**:將重複的樣式邏輯封裝為修飾器,提升代碼複用率。
## 導航架構 (Navigation)
使用 `NavigationStack` 結合 `NavigationPath` 實現類型安全且可程式化控制的路由系統。建議將路由邏輯收納於一個 `@Observable` 的 Router 類別中。
## 效能優化 (Performance)
- **延遲加載**:對於大型集合,使用 `LazyVStack``LazyHStack`
- **穩定標識符**:在 `ForEach` 中務必使用穩定且唯一的 ID避免使用陣列索引。
- **避免耗時運算**:嚴禁在 `body` 內執行 I/O、網路或大量運算。非同步任務請使用 `.task {}` 修飾器(它會在視圖消失時自動取消任務)。
- **Equatable 順應性**:對於渲染成本極高的視圖,實作 `Equatable` 以跳過不必要的重複渲染。
## 應避免的反模式
- 在新專案中繼續使用 `ObservableObject` / `@Published` 等舊版 API。
- 使用 `AnyView` 類型抹除,應優先考慮 `@ViewBuilder`、`Group` 或 `switch`
-`body``init` 內直接發起非同步請求。
- 忽視跨 Actor 傳遞數據時的 `Sendable` 需求。