帮助 Swift 开发者实现基于 Actor 的线程安全内存与文件持久化方案
复制安装指令,让 AI 自动完成配置 · 推荐新手
请帮我安装 askskill 上的 "swift-actor-persistence" 技能: 1. 下载 https://raw.githubusercontent.com/affaan-m/ECC/main/skills/swift-actor-persistence/SKILL.md 2. 保存为 ~/.claude/skills/swift-actor-persistence/SKILL.md 3. 装好后重载技能,告诉我可以用了
请用 Swift 设计一个基于 actor 的本地持久化仓库,包含内存缓存和文件落盘能力,支持保存、读取、删除 Codable 用户设置,并说明如何避免数据竞争。
一套基于 Swift actor 的持久化代码结构,含核心接口、示例实现与线程安全说明。
下面这段 Swift 存储代码在多线程下可能有竞态问题,请将其重构为 actor 模式,并加入内存缓存与文件备份策略,同时保留原有 API 的主要用法。
重构后的 actor 版本代码、迁移说明,以及并发安全性改进点列表。
请为一个使用 actor 的 Swift 持久化模块编写测试方案,覆盖缓存命中、文件读写、并发访问一致性、异常恢复,并给出 XCTest 示例。
包含测试用例清单、并发测试思路与 XCTest 示例代码的完整测试方案。
Patterns for building thread-safe data persistence layers using Swift actors. Combines in-memory caching with file-backed storage, leveraging the actor model to eliminate data races at compile time.
The actor model guarantees serialized access — no data races, enforced by the compiler.
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)
// Synchronous load during init (actor isolation not yet active)
self.cache = Self.loadSynchronously(from: fileURL)
}
// MARK: - Public API
public func save(_ item: T) throws {
cache[item.id] = item
try persistToFile()
}
public func delete(_ id: String) throws {
cache[id] = nil
try persistToFile()
}
public func find(by id: String) -> T? {
cache[id]
}
public func loadAll() -> [T] {
Array(cache.values)
}
// MARK: - Private
private func persistToFile() throws {
let data = try JSONEncoder().encode(Array(cache.values))
try data.write(to: fileURL, options: .atomic)
}
private static func loadSynchronously(from url: URL) -> [String: T] {
guard let data = try? Data(contentsOf: url),
let items = try? JSONDecoder().decode([T].self, from: data) else {
return [:]
}
return Dictionary(uniqueKeysWithValues: items.map { ($0.id, $0) })
}
}
All calls are automatically async due to actor isolation:
let repository = LocalRepository<Question>()
// Read — fast O(1) lookup from in-memory cache
let question = await repository.find(by: "q-001")
let allQuestions = await repository.loadAll()
// Write — updates cache and persists to file atomically
try await repository.save(newQuestion)
try await repository.delete("q-001")
@Observable
final class QuestionListViewModel {
private(set) var questions: [Question] = []
private let repository: LocalRepository<Question>
init(repository: LocalRepository<Question> = LocalRepository()) {
self.repository = repository
}
func load() async {
questions = await repository.loadAll()
}
func add(_ question: Question) async throws {
try await repository.save(question)
questions = await repository.loadAll()
}
}
| Decision | Rationale |
|---|---|
| Actor (not class + lock) | Compiler-enforced thread safety, no manual synchronization |
| In-memory cache + file persistence | Fast reads from cache, durable writes to disk |
| Synchronous init loading | Avoids async initialization complexity |
| Dictionary keyed by ID | O(1) lookups by identifier |
Generic over Codable & Identifiable | Reusable across any model type |
Atomic file writes (.atomic) | Prevents partial writes on crash |
Sendable types for all data crossing actor boundaries.atomic writes to prevent data corruption if the app crashes mid-writeinit — async initializers add complexity with minimal benefit for local files@Observable ViewModels for reactive UI updates…
帮助开发者掌握 Ktor 服务端常用模式、认证依赖注入与测试实践。
帮助团队编排多代理协作流程,管理任务归属、看板流转与交接控制。
帮助开发者为代码代理配置性能优化、安全防护与研究优先工作流。
为 Windows 原生桌面应用生成并执行端到端自动化测试流程。
为 TypeScript、JavaScript、React 与 Node.js 提供统一编码规范与最佳实践建议
帮助用户掌握 Go 测试模式与 TDD,编写可靠的单元测试、基准与覆盖率分析。
帮助开发者用 Swift actor 构建线程安全的数据持久化与缓存方案
帮助开发者理解 Swift 6.2 并发模型变化与安全使用方式。
帮助开发者理解 Swift 6.2 并发模型与主线程隔离的最佳实践。
帮助开发者依据 Swift 并发迁移指南,规划并执行代码迁移与问题修复。
为 AI 编码工具补充 Swift 并发专家指导,提升安全性、性能与 Swift 6 迁移效率。
帮助 Swift 开发者用协议依赖注入编写可测试代码并高效构建 Mock。