claude-code/claude-zh/skills/swift-actor-persistence/SKILL.md

81 lines
3.0 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: swift-actor-persistence
description: 在 Swift 中使用 Actors 進行線程安全的資料持久化 — 結合記憶體快取與檔案儲存,從設計上消除資料競爭 (Data Races)。
---
# 使用 Swift Actors 達成線程安全持久化
這是在 Swift 中使用 Actor 構建線程安全資料持久層的模式。它結合了記憶體快取 (In-memory cache) 與磁碟檔案存儲,利用 Actor 模型在編譯時期即消除資料競爭風險。
## 何時啟用
- 在 Swift 5.5+ 環境下構建資料持久層。
- 對共享的可變狀態 (Shared Mutable State) 需要線程安全存取。
- 希望淘汰手動同步機制(如 Locks, DispatchQueue
- 開發具備本地存儲能力的離線優先 (Offline-first) 應用程式。
## 核心模式:基於 Actor 的 Repository
Actor 模型保證了序列化存取 — 由編譯器強制執行單一時間點僅有一個任務能存取其內部狀態。
```swift
public actor LocalRepository<T: Codable & Identifiable> where T.ID == String {
private var cache: [String: T] = [:]
private let fileURL: URL
public init(directory: URL = .documentsDirectory, filename: String = "data.json") {
self.fileURL = directory.appendingPathComponent(filename)
// 在 init 期間同步載入(此時 Actor Isolation 尚未啟用)
self.cache = Self.loadSynchronously(from: fileURL)
}
// 提供給外部使用的線程安全 API
public func save(_ item: T) throws {
cache[item.id] = item
try persistToFile()
}
public func find(by id: String) -> T? {
cache[id]
}
// 私有實作:原子化寫入檔案以防止損毀
private func persistToFile() throws {
let data = try JSONEncoder().encode(Array(cache.values))
try data.write(to: fileURL, options: .atomic)
}
}
```
## 使用方式
由於 Actor 隔離機制,所有外部調用皆會自動轉換為 `async` 行為:
```swift
let repository = LocalRepository<User>()
// 讀取 — 從記憶體快取中進行極速 O(1) 查找
let user = await repository.find(by: "u-001")
// 寫入 — 同步更新快取並原子化持久化至磁碟
try await repository.save(newUser)
```
## 實踐之最佳實踐
- **使用 `Sendable` 類型**:確保所有跨越 Actor 邊界的資料皆符合 Sendable 協定。
- **內部實作封裝**Actor 的公開 API 應僅暴露業務邏輯操作,隱藏持久化細節。
- **原子化寫入 (`.atomic`)**:防止 App 在寫入中途崩潰導致資料損毀。
- **配合 `@Observable`**:在 ViewModel 中使用,為 UI 提供反應式數據更新。
## 應避免的反模式
- 在新的 Swift Concurrency 程式碼中繼續混用 `DispatchQueue``NSLock`
- 對外暴露內部的 Cache 字典。
- 使用 `nonisolated` 關鍵字來規避 Actor 隔離(這會破壞線程安全性)。
## 適用情境
- iOS/macOS 應用的本地資料存儲(用戶資料、偏好設定、快取內容)。
- 需要更換舊有的 `DispatchQueue` 式同步邏輯,轉向現代化 Swift Concurrency 架構。