swift-actor-persistence
npx skills add https://github.com/shimo4228/claude-code-learned-skills --skill swift-actor-persistence
Agent 安装分布
Skill 文档
Swift Actors for Thread-Safe Persistence
ã¹ã¬ããã»ã¼ããªæ°¸ç¶åã®ããã®Swift Actor
Extracted / æ½åºæ¥: 2026-02-05 Context / ã³ã³ããã¹ã: iOS/Swift apps requiring thread-safe data persistence with async/await async/awaitã使ç¨ããã¹ã¬ããã»ã¼ããªãã¼ã¿æ°¸ç¶åãå¿ è¦ãªiOS/Swiftã¢ããª
Problem / 課é¡
Data persistence layers often face race conditions when multiple parts of an app read/write simultaneously. Traditional approaches (DispatchQueues, locks) are error-prone and verbose.
ãã¼ã¿æ°¸ç¶åã¬ã¤ã¤ã¼ã¯ãã¢ããªã®è¤æ°ã®é¨åãåæã«èªã¿æ¸ãããéã«ã¬ã¼ã¹ã³ã³ãã£ã·ã§ã³ã«ç´é¢ãããã¨ãå¤ãã徿¥ã®ã¢ããã¼ãï¼DispatchQueuesãããã¯ï¼ã¯ã¨ã©ã¼ãçºçãããããåé·ã«ãªããã¡ã
Solution / 解決ç
Use Swift actors to isolate all persistence state and operations. The actor model guarantees:
- No data races (compiler-enforced)
- Automatic serialization of access
- Async-first API that integrates with structured concurrency
Swift actorã使ç¨ãã¦ããã¹ã¦ã®æ°¸ç¶åç¶æ ã¨æä½ãåé¢ãããactorã¢ãã«ã¯ä»¥ä¸ãä¿è¨¼ï¼
- ãã¼ã¿ç«¶åãªãï¼ã³ã³ãã¤ã©ã«ããå¼·å¶ï¼
- ã¢ã¯ã»ã¹ã®èªåã·ãªã¢ã©ã¤ãº
- æ§é åä¸¦è¡æ§ã¨çµ±åãããasyncãã¡ã¼ã¹ãAPI
public actor LocalRepository {
private var cache: [String: Record] = [:]
private let cacheFileURL: URL
public init(directory: URL = .documentsDirectory) {
self.cacheFileURL = directory.appendingPathComponent("cache.json")
// Synchronous cache load during init (actor isolation not yet active)
// initä¸ã®åæãã£ãã·ã¥èªã¿è¾¼ã¿ï¼actoråé¢ãã¾ã ã¢ã¯ãã£ãã§ãªãããï¼
self.cache = Self.loadCacheSynchronously(from: cacheFileURL)
}
public func save(_ record: Record) throws {
cache[record.id] = record
try persistToFile()
}
public func loadAll() -> [Record] {
Array(cache.values)
}
public func find(by id: String) -> Record? {
cache[id]
}
private func persistToFile() throws {
let data = try JSONEncoder().encode(Array(cache.values))
try data.write(to: cacheFileURL)
}
private static func loadCacheSynchronously(from url: URL) -> [String: Record] {
guard let data = try? Data(contentsOf: url),
let records = try? JSONDecoder().decode([Record].self, from: data) else {
return [:]
}
return Dictionary(uniqueKeysWithValues: records.map { ($0.id, $0) })
}
}
Key Patterns / 主è¦ãã¿ã¼ã³
- In-memory cache + file persistence / ã¤ã³ã¡ã¢ãªãã£ãã·ã¥ + ãã¡ã¤ã«æ°¸ç¶å: Fast reads from cache, durable writes to disk / ãã£ãã·ã¥ããã®é«éèªã¿åãããã£ã¹ã¯ã¸ã®æ°¸ç¶æ¸ãè¾¼ã¿
- Synchronous init loading / åæçãªåæåèªã¿è¾¼ã¿: Avoids async initialization complexity / éåæåæåã®è¤éããåé¿
- Dictionary keying / Dictionaryåã«ãããã¼ç®¡ç: O(1) lookups by ID / IDã«ããO(1)ã®æ¤ç´¢
- Private persistence / ãã©ã¤ãã¼ããªæ°¸ç¶å: External callers only see domain operations / å¤é¨å¼ã³åºãå ã¯ãã¡ã¤ã³æä½ã®ã¿ãåç §
Usage / ä½¿ç¨æ¹æ³
let repository = LocalRepository()
// All calls are async due to actor isolation
// actoråé¢ã«ããããã¹ã¦ã®å¼ã³åºãã¯éåæ
let records = await repository.loadAll()
try await repository.save(newRecord)
let found = await repository.find(by: "question-1")
When to Use / 使ç¨ãã¹ãå ´é¢
- Building a data persistence layer in Swift 5.5+ / Swift 5.5以éã§ãã¼ã¿æ°¸ç¶åã¬ã¤ã¤ã¼ãæ§ç¯ããå ´å
- Need thread-safe access to shared state / å ±æç¶æ ã¸ã®ã¹ã¬ããã»ã¼ããªã¢ã¯ã»ã¹ãå¿ è¦ãªå ´å
- Want to avoid manual synchronization (locks, queues) / æååæï¼ããã¯ããã¥ã¼ï¼ãé¿ãããå ´å
- Building offline-first apps with local storage / ãã¼ã«ã«ã¹ãã¬ã¼ã¸ã使ç¨ãããªãã©ã¤ã³ãã¡ã¼ã¹ãã¢ããªãæ§ç¯ããå ´å
Related Patterns / é¢é£ãã¿ã¼ã³
- Combine with
@ObservableViewModels for UI binding / UIãã¤ã³ãã£ã³ã°ç¨ã«@ObservableViewModelã¨çµã¿åããã - Use
Sendabletypes for data crossing actor boundaries / actorå¢çãè¶ãããã¼ã¿ã«ã¯Sendableåãä½¿ç¨ - Consider
FileBasedSyncManageractor for cloud sync operations / ã¯ã©ã¦ãåææä½ã«ã¯FileBasedSyncManageractorãæ¤è¨