$ loading_
帮助开发者用 Swift actor 构建线程安全的数据持久化与缓存方案
复制安装指令,让 AI 自动完成配置 · 推荐新手
请帮我安装 askskill 上的 "swift-actor-persistence" 技能: 1. 下载 https://raw.githubusercontent.com/affaan-m/ECC/main/docs/ja-JP/skills/swift-actor-persistence/SKILL.md 2. 保存为 ~/.claude/skills/swift-actor-persistence/SKILL.md 3. 装好后重载技能,告诉我可以用了
请用 Swift 设计一个基于 actor 的本地数据持久化组件,要求包含内存缓存、文件存储、异步读写接口,以及避免数据竞争的实现说明。
一套线程安全的 Swift actor 持久化方案示例,含核心代码结构与设计说明。
把现有使用 DispatchQueue 和共享字典的 Swift 存储逻辑重构为 actor 模式,保留缓存能力,并支持落盘保存与读取恢复。
重构后的 actor 版本代码,以及从旧并发模型迁移到新实现的建议。
为一个基于 Swift actor 的缓存加文件持久化模块编写测试方案,覆盖并发访问、数据一致性、文件恢复和错误处理场景。
包含测试思路、关键用例和示例测试代码的完整测试方案。
Swiftのactorを使用してスレッドセーフなデータ永続化レイヤーを構築するパターン。メモリキャッシュとファイルバックドストレージを組み合わせ、actorモデルを活用してコンパイル時にデータ競合を排除する。
Actorモデルはシリアライズされたアクセスを保証する——コンパイラによって強制されるデータ競合なし。
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 {
let previous = cache[item.id]
cache[item.id] = item
do {
try persistToFile()
} catch {
// ディスク書き込み失敗時はキャッシュをロールバックして整合性を維持
cache[item.id] = previous
throw error
}
}
public func delete(_ id: String) throws {
let previous = cache[id]
cache[id] = nil
do {
try persistToFile()
} catch {
// ディスク書き込み失敗時はキャッシュをロールバックして整合性を維持
cache[id] = previous
throw error
}
}
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) })
}
}
Actorの分離により、すべての呼び出しは自動的に非同期になる:
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()
}
}
| 決定 | 理由 |
|---|---|
| Actorを使用(クラス + ロックではなく) | コンパイラによって強制されるスレッド安全性、手動同期不要 |
| メモリキャッシュ + ファイル永続化 | キャッシュからの高速読み取り、ディスクへの永続的な書き込み |
| 初期化時の同期ロード | 非同期初期化の複雑さを回避 |
| IDをキーとする辞書 | 識別子によるO(1)検索 |
ジェネリック Codable & Identifiable | あらゆるモデル型で再利用可能 |
アトミックなファイル書き込み(.atomic) | クラッシュ時の部分書き込みを防ぐ |
Sendable 型を使用する.atomic 書き込みを使用する —— 書き込み中のアプリクラッシュによるデータ破損を防ぐinit で同期的にロードする —— 非同期イニシャライザはローカルファイルに対するわずかな利点のために複雑さが増す@Observable ViewModelと組み合わせる —— リアクティブなUI更新を実現するDispatchQueue または NSLock を使用するawait であることを忘れる——呼び出し元は非同期コンテキストを処理する必要があるnonisolated を使用する(本末転倒)…
为 TypeScript、JavaScript、React 与 Node.js 提供统一编码规范与最佳实践建议
帮助开发者掌握 Ktor 服务端常用模式、认证依赖注入与测试实践。
帮助开发者为代码代理配置性能优化、安全防护与研究优先工作流。
为 Windows 原生桌面应用生成并执行端到端自动化测试流程。
帮助 Swift 开发者实现基于 Actor 的线程安全内存与文件持久化方案
帮助团队编排多代理协作流程,管理任务归属、看板流转与交接控制。
帮助开发者理解 Swift 6.2 并发模型与主线程隔离的最佳实践。
帮助开发者理解 Swift 6.2 并发模型变化与安全使用方式。
帮助开发者依据 Swift 并发迁移指南,规划并执行代码迁移与问题修复。
为 AI 编码工具补充 Swift 并发专家指导,提升安全性、性能与 Swift 6 迁移效率。