[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6G2CT8F5R9BT2D0MXV526PP":3,"skill-same:01M6G2CT8F5R9BT2D0MXV526PP":59},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":30,"linkOnly":31,"markdownContent":32,"markdownBody":33,"frontMatter":34,"refName":36,"commitSha":37,"skillDirectory":38,"forksCount":39,"repositoryHtmlUrl":40,"repositoryHomepageUrl":6,"ownerHtmlUrl":41,"ownerBlogUrl":42,"ownerDescription":43,"updatedAt":44,"install":45,"resources":58},"01M6G2CT8F5R9BT2D0MXV526PP","swift-actor-persistence",null,"在 Swift 中使用 actor 实现线程安全的数据持久化——基于内存缓存与文件支持的存储，通过设计消除数据竞争。","oabdelmaksoud\u002FAgention","oabdelmaksoud","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F50699149?v=4","01M6D5CVVN778ZCDP1WHS816SP","Omar Abdelmaksoud","01M6D8A4TE76V3DCSH3D94VG1V",2,"MIT","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fdocs\u002Fzh-CN\u002Fskills\u002Fswift-actor-persistence\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计","SCENARIO","使用场景",[24,25,26,27,28,29],"swift","persistence","swift actor persistence","design","安全","文件","2026-11-10 10:12:30",false,"---\nname: swift-actor-persistence\ndescription: 在 Swift 中使用 actor 实现线程安全的数据持久化——基于内存缓存与文件支持的存储，通过设计消除数据竞争。\norigin: ECC\n---\n\n# 用于线程安全持久化的 Swift Actor\n\n使用 Swift actor 构建线程安全数据持久化层的模式。结合内存缓存与文件支持的存储，利用 actor 模型在编译时消除数据竞争。\n\n## 何时激活\n\n* 在 Swift 5.5+ 中构建数据持久化层\n* 需要对共享可变状态进行线程安全访问\n* 希望消除手动同步（锁、DispatchQueue）\n* 构建具有本地存储的离线优先应用\n\n## 核心模式\n\n### 基于 Actor 的存储库\n\nActor 模型保证了序列化访问 —— 没有数据竞争，由编译器强制执行。\n\n```swift\npublic actor LocalRepository\u003CT: Codable & Identifiable> where T.ID == String {\n    private var cache: [String: T] = [:]\n    private let fileURL: URL\n\n    public init(directory: URL = .documentsDirectory, filename: String = \"data.json\") {\n        self.fileURL = directory.appendingPathComponent(filename)\n        \u002F\u002F Synchronous load during init (actor isolation not yet active)\n        self.cache = Self.loadSynchronously(from: fileURL)\n    }\n\n    \u002F\u002F MARK: - Public API\n\n    public func save(_ item: T) throws {\n        cache[item.id] = item\n        try persistToFile()\n    }\n\n    public func delete(_ id: String) throws {\n        cache[id] = nil\n        try persistToFile()\n    }\n\n    public func find(by id: String) -> T? {\n        cache[id]\n    }\n\n    public func loadAll() -> [T] {\n        Array(cache.values)\n    }\n\n    \u002F\u002F MARK: - Private\n\n    private func persistToFile() throws {\n        let data = try JSONEncoder().encode(Array(cache.values))\n        try data.write(to: fileURL, options: .atomic)\n    }\n\n    private static func loadSynchronously(from url: URL) -> [String: T] {\n        guard let data = try? Data(contentsOf: url),\n              let items = try? JSONDecoder().decode([T].self, from: data) else {\n            return [:]\n        }\n        return Dictionary(uniqueKeysWithValues: items.map { ($0.id, $0) })\n    }\n}\n```\n\n### 用法\n\n由于 actor 隔离，所有调用都会自动变为异步：\n\n```swift\nlet repository = LocalRepository\u003CQuestion>()\n\n\u002F\u002F Read — fast O(1) lookup from in-memory cache\nlet question = await repository.find(by: \"q-001\")\nlet allQuestions = await repository.loadAll()\n\n\u002F\u002F Write — updates cache and persists to file atomically\ntry await repository.save(newQuestion)\ntry await repository.delete(\"q-001\")\n```\n\n### 与 @Observable ViewModel 结合使用\n\n```swift\n@Observable\nfinal class QuestionListViewModel {\n    private(set) var questions: [Question] = []\n    private let repository: LocalRepository\u003CQuestion>\n\n    init(repository: LocalRepository\u003CQuestion> = LocalRepository()) {\n        self.repository = repository\n    }\n\n    func load() async {\n        questions = await repository.loadAll()\n    }\n\n    func add(_ question: Question) async throws {\n        try await repository.save(question)\n        questions = await repository.loadAll()\n    }\n}\n```\n\n## 关键设计决策\n\n| 决策 | 理由 |\n|----------|-----------|\n| Actor（而非类 + 锁） | 编译器强制执行的线程安全性，无需手动同步 |\n| 内存缓存 + 文件持久化 | 从缓存中快速读取，持久化写入磁盘 |\n| 同步初始化加载 | 避免异步初始化的复杂性 |\n| 按 ID 键控的字典 | 按标识符进行 O(1) 查找 |\n| 泛型化 `Codable & Identifiable` | 可在任何模型类型中重复使用 |\n| 原子文件写入 (`.atomic`) | 防止崩溃时部分写入 |\n\n## 最佳实践\n\n* **对所有跨越 actor 边界的数据使用 `Sendable` 类型**\n* **保持 actor 的公共 API 最小化** —— 仅暴露领域操作，而非持久化细节\n* **使用 `.atomic` 写入** 以防止应用在写入过程中崩溃导致数据损坏\n* **在 `init` 中同步加载** —— 异步初始化器会增加复杂性，而对本地文件的益处微乎其微\n* **与 `@Observable` ViewModel 结合使用** 以实现响应式 UI 更新\n\n## 应避免的反模式\n\n* 在 Swift 并发新代码中使用 `DispatchQueue` 或 `NSLock` 而非 actor\n* 将内部缓存字典暴露给外部调用者\n* 在不进行验证的情况下使文件 URL 可配置\n* 忘记所有 actor 方法调用都是 `await` —— 调用者必须处理异步上下文\n* 使用 `nonisolated` 来绕过 actor 隔离（违背了初衷）\n\n## 何时使用\n\n* iOS\u002FmacOS 应用中的本地数据存储（用户数据、设置、缓存内容）\n* 稍后同步到服务器的离线优先架构\n* 应用中多个部分并发访问的任何共享可变状态\n* 用现代 Swift 并发性替换基于 `DispatchQueue` 的旧式线程安全机制\n","# 用于线程安全持久化的 Swift Actor\n\n使用 Swift actor 构建线程安全数据持久化层的模式。结合内存缓存与文件支持的存储，利用 actor 模型在编译时消除数据竞争。\n\n## 何时激活\n\n* 在 Swift 5.5+ 中构建数据持久化层\n* 需要对共享可变状态进行线程安全访问\n* 希望消除手动同步（锁、DispatchQueue）\n* 构建具有本地存储的离线优先应用\n\n## 核心模式\n\n### 基于 Actor 的存储库\n\nActor 模型保证了序列化访问 —— 没有数据竞争，由编译器强制执行。\n\n```swift\npublic actor LocalRepository\u003CT: Codable & Identifiable> where T.ID == String {\n    private var cache: [String: T] = [:]\n    private let fileURL: URL\n\n    public init(directory: URL = .documentsDirectory, filename: String = \"data.json\") {\n        self.fileURL = directory.appendingPathComponent(filename)\n        \u002F\u002F Synchronous load during init (actor isolation not yet active)\n        self.cache = Self.loadSynchronously(from: fileURL)\n    }\n\n    \u002F\u002F MARK: - Public API\n\n    public func save(_ item: T) throws {\n        cache[item.id] = item\n        try persistToFile()\n    }\n\n    public func delete(_ id: String) throws {\n        cache[id] = nil\n        try persistToFile()\n    }\n\n    public func find(by id: String) -> T? {\n        cache[id]\n    }\n\n    public func loadAll() -> [T] {\n        Array(cache.values)\n    }\n\n    \u002F\u002F MARK: - Private\n\n    private func persistToFile() throws {\n        let data = try JSONEncoder().encode(Array(cache.values))\n        try data.write(to: fileURL, options: .atomic)\n    }\n\n    private static func loadSynchronously(from url: URL) -> [String: T] {\n        guard let data = try? Data(contentsOf: url),\n              let items = try? JSONDecoder().decode([T].self, from: data) else {\n            return [:]\n        }\n        return Dictionary(uniqueKeysWithValues: items.map { ($0.id, $0) })\n    }\n}\n```\n\n### 用法\n\n由于 actor 隔离，所有调用都会自动变为异步：\n\n```swift\nlet repository = LocalRepository\u003CQuestion>()\n\n\u002F\u002F Read — fast O(1) lookup from in-memory cache\nlet question = await repository.find(by: \"q-001\")\nlet allQuestions = await repository.loadAll()\n\n\u002F\u002F Write — updates cache and persists to file atomically\ntry await repository.save(newQuestion)\ntry await repository.delete(\"q-001\")\n```\n\n### 与 @Observable ViewModel 结合使用\n\n```swift\n@Observable\nfinal class QuestionListViewModel {\n    private(set) var questions: [Question] = []\n    private let repository: LocalRepository\u003CQuestion>\n\n    init(repository: LocalRepository\u003CQuestion> = LocalRepository()) {\n        self.repository = repository\n    }\n\n    func load() async {\n        questions = await repository.loadAll()\n    }\n\n    func add(_ question: Question) async throws {\n        try await repository.save(question)\n        questions = await repository.loadAll()\n    }\n}\n```\n\n## 关键设计决策\n\n| 决策 | 理由 |\n|----------|-----------|\n| Actor（而非类 + 锁） | 编译器强制执行的线程安全性，无需手动同步 |\n| 内存缓存 + 文件持久化 | 从缓存中快速读取，持久化写入磁盘 |\n| 同步初始化加载 | 避免异步初始化的复杂性 |\n| 按 ID 键控的字典 | 按标识符进行 O(1) 查找 |\n| 泛型化 `Codable & Identifiable` | 可在任何模型类型中重复使用 |\n| 原子文件写入 (`.atomic`) | 防止崩溃时部分写入 |\n\n## 最佳实践\n\n* **对所有跨越 actor 边界的数据使用 `Sendable` 类型**\n* **保持 actor 的公共 API 最小化** —— 仅暴露领域操作，而非持久化细节\n* **使用 `.atomic` 写入** 以防止应用在写入过程中崩溃导致数据损坏\n* **在 `init` 中同步加载** —— 异步初始化器会增加复杂性，而对本地文件的益处微乎其微\n* **与 `@Observable` ViewModel 结合使用** 以实现响应式 UI 更新\n\n## 应避免的反模式\n\n* 在 Swift 并发新代码中使用 `DispatchQueue` 或 `NSLock` 而非 actor\n* 将内部缓存字典暴露给外部调用者\n* 在不进行验证的情况下使文件 URL 可配置\n* 忘记所有 actor 方法调用都是 `await` —— 调用者必须处理异步上下文\n* 使用 `nonisolated` 来绕过 actor 隔离（违背了初衷）\n\n## 何时使用\n\n* iOS\u002FmacOS 应用中的本地数据存储（用户数据、设置、缓存内容）\n* 稍后同步到服务器的离线优先架构\n* 应用中多个部分并发访问的任何共享可变状态\n* 用现代 Swift 并发性替换基于 `DispatchQueue` 的旧式线程安全机制\n",{"name":5,"origin":35,"description":7},"ECC","main","a318f48de3c5718e8ea2e9f6fae7790e8a759e85","upstream-sync\u002Fwork\u002Fecc\u002Fdocs\u002Fzh-CN\u002Fskills\u002Fswift-actor-persistence",0,"https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fo-abdelmaksoud\u002F","Full-Stack Engineer | AI Systems Architect | Building autonomous multi-agent systems","2026-03-08 21:23:03",{"source":8,"skillName":5,"commands":46,"prompt":56,"zipAvailable":57},[47,50,53],{"tool":48,"command":49},"npx","npx skills add oabdelmaksoud\u002FAgention --skill swift-actor-persistence",{"tool":51,"command":52},"bunx","bunx skills add oabdelmaksoud\u002FAgention --skill swift-actor-persistence",{"tool":54,"command":55},"pnpm","pnpm dlx skills add oabdelmaksoud\u002FAgention --skill swift-actor-persistence","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fdocs\u002Fzh-CN\u002Fskills\u002Fswift-actor-persistence\u002FSKILL.md",true,[],[60,82,96,129,155,174],{"skillNo":61,"name":62,"nameZh":6,"description":63,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":64,"categories":65,"keywords":69,"publishedAt":30},"01M6G2QFCBNBYAJF2KTK85G9A6","visa-doc-translate","Translate visa application documents (images) to English and create a bilingual PDF with original and translation","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fvisa-doc-translate\u002FSKILL.md",[66],{"categoryNo":67,"categoryName":68,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000002","文档处理",[70,71,72,73,74,75,76,77,78,79,80,81],"translate","doc","visa doc translate","bilingual","with","english","application","PDF","translation","documents","create","images",{"skillNo":83,"name":84,"nameZh":6,"description":85,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":86,"categories":87,"keywords":88,"publishedAt":30},"01M6G2QB09TSK6BY4ME5X20EVQ","verification-loop","A comprehensive verification system for Claude Code sessions.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fverification-loop\u002FSKILL.md",[],[89,90,91,92,93,94,95],"verification","loop","verification loop","sessions","code","claude code sessions","system",{"skillNo":97,"name":98,"nameZh":6,"description":99,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":100,"categories":101,"keywords":113,"publishedAt":30},"01M6G2Q6V2F7G03VAAF27FXPJR","tdd-workflow","Use this skill when writing new features, fixing bugs, or refactoring code. Enforces test-driven development with 80%+ coverage including unit, integration, and E2E tests.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Ftdd-workflow\u002FSKILL.md",[102,105,108],{"categoryNo":103,"categoryName":104,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":106,"categoryName":107,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":109,"categoryName":110,"taxonomyType":111,"taxonomyTypeDesc":112},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[114,115,116,117,118,119,120,121,122,93,123,124,125,126,74,127,128],"workflow","tdd","tdd workflow","use","unit","coverage","refactoring","e2e","integration","development","e2e tests","tests","driven","test","writing",{"skillNo":130,"name":131,"nameZh":6,"description":132,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":133,"categories":134,"keywords":135,"publishedAt":30},"01M6G2Q359YJRWAR2PFCEQAXF3","swiftui-patterns","SwiftUI architecture patterns, state management with @Observable, view composition, navigation, performance optimization, and modern iOS\u002FmacOS UI best practices.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fswiftui-patterns\u002FSKILL.md",[],[136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,74],"patterns","swiftui","swiftui patterns","architecture","macos","performance","state management","best practices","state","ui","Optimization","ios","architecture patterns","Composition","performance optimization","view","management","swiftui architecture","navigation",{"skillNo":156,"name":157,"nameZh":6,"description":158,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":159,"categories":160,"keywords":162,"publishedAt":30},"01M6G2PY8B2FWZTWPZ84H83Y7C","swift-protocol-di-testing","Protocol-based dependency injection for testable Swift code — mock file system, network, and external APIs using focused protocols and Swift Testing.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fswift-protocol-di-testing\u002FSKILL.md",[161],{"categoryNo":103,"categoryName":104,"taxonomyType":21,"taxonomyTypeDesc":22},[163,164,24,165,93,166,167,168,169,95,170,171,172,173],"swift protocol di testing","protocol","testing","protocols","file","network","injection","dependency","swift testing","dependency injection","mock",{"skillNo":175,"name":176,"nameZh":6,"description":177,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":178,"categories":179,"keywords":180,"publishedAt":30},"01M6G2PSCN2GXV9FFZDRRRWVB6","swift-concurrency-6-2","Swift 6.2 Approachable Concurrency — single-threaded by default, @concurrent for explicit background offloading, isolated conformances for main actor types.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fswift-concurrency-6-2\u002FSKILL.md",[],[181,182,183,24,184,36,185],"concurrency","swift concurrency","swift concurrency 6 2","default","types"]