swift-actor-persistence

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Swift Actors for Thread-Safe Persistence

用于线程安全持久化的Swift Actors

スレッドセーフな永続化のためのSwift Actor

Extracted / 抽出日: 2026-02-05 Context / コンテキスト: iOS/Swift apps requiring thread-safe data persistence with async/await async/awaitを使用したスレッドセーフなデータ永続化が必要なiOS/Swiftアプリ

提取日期: 2026-02-05 适用场景: 需要使用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、ロック)はエラーが発生しやすく、冗長になりがち。

数据持久化层在应用的多个部分同时进行读写操作时,经常会遇到竞态条件问题。传统的解决方案(如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
swift
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) })
    }
}

使用Swift Actor来隔离所有持久化状态和操作。Actor模型可以保证:
  • 无数据竞争(由编译器强制保障)
  • 自动序列化访问
  • 与结构化并发集成的异步优先API
swift
public actor LocalRepository {
    private var cache: [String: Record] = [:]
    private let cacheFileURL: URL

    public init(directory: URL = .documentsDirectory) {
        self.cacheFileURL = directory.appendingPathComponent("cache.json")
        // 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 / 主要パターン

核心模式

  1. In-memory cache + file persistence / インメモリキャッシュ + ファイル永続化: Fast reads from cache, durable writes to disk / キャッシュからの高速読み取り、ディスクへの永続書き込み
  2. Synchronous init loading / 同期的な初期化読み込み: Avoids async initialization complexity / 非同期初期化の複雑さを回避
  3. Dictionary keying / Dictionary型によるキー管理: O(1) lookups by ID / IDによるO(1)の検索
  4. Private persistence / プライベートな永続化: External callers only see domain operations / 外部呼び出し元はドメイン操作のみを参照

  1. 内存缓存+文件持久化: 从缓存快速读取,写入磁盘保证持久化
  2. 同步初始化加载: 避免异步初始化的复杂性
  3. 字典键值管理: 通过ID实现O(1)时间复杂度的查找
  4. 私有持久化实现: 外部调用者仅能看到领域相关操作

Usage / 使用方法

使用方法

swift
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")

swift
let repository = LocalRepository()

// 由于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 / ローカルストレージを使用したオフラインファーストアプリを構築する場合

  • 在Swift 5.5及以上版本中构建数据持久化层时
  • 需要对共享状态进行线程安全访问时
  • 希望避免手动同步(锁、队列)时
  • 构建基于本地存储的离线优先应用时

Related Patterns / 関連パターン

相关模式

  • Combine with
    @Observable
    ViewModels for UI binding / UIバインディング用に
    @Observable
    ViewModelと組み合わせる
  • Use
    Sendable
    types for data crossing actor boundaries / actor境界を越えるデータには
    Sendable
    型を使用
  • Consider
    FileBasedSyncManager
    actor for cloud sync operations / クラウド同期操作には
    FileBasedSyncManager
    actorを検討
  • @Observable
    ViewModel结合用于UI绑定
  • 跨Actor边界的数据使用
    Sendable
    类型
  • 云同步操作可考虑使用
    FileBasedSyncManager
    Actor