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

81 lines
3.0 KiB
Markdown
Raw Normal View History

2026-02-27 13:45:37 +00:00
---
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 架構。