Realm Swfit 异步写入方法

问题描述 投票:0回答:2

我对快速并发尤其是 Realm Swift 很陌生。我有 2 个示例代码,我认为它们是相同的,但它不起作用

下面是无效代码的示例

var localRealm: Realm {
    get {
        return try! Realm()
    }
}
fileprivate func testAsyncRealm() {
    self.localRealm.beginAsyncWrite {
        self.localRealm.create(SwiftStringObject.self, value: ["string2"])
        self.localRealm.commitAsyncWrite(allowGrouping: true) { error in
            print(error)
        }
    }
}

这段代码会抛出异常

Terminating app due to uncaught exception 'RLMException', reason: Can only add, remove, or create objects in a Realm in a write transaction - call beginWriteTransaction on an RLMRealm instance first.

但是,下面的代码可以正常工作

fileprivate func testAsyncRealm() {
    let realm = try! Realm()
    realm.beginAsyncWrite {
        realm.create(SwiftStringObject.self, value: ["string2"])
        realm.commitAsyncWrite(allowGrouping: true) { error in
            print(error)
        }
    }
}

我在这里缺少什么?谢谢...

领域版本:10.40.0

realm realm-mobile-platform
2个回答
1
投票

这只是一个理论,但符合问题

当领域对象开始异步写入事务时,似乎在该领域上设置了一个标志

isPerformingAsynchronousWriteOperations
以指示它处于异步写入中。例如

var realm = try! Realm()
        
realm.beginAsyncWrite {
   let isWrite = realm.isPerformingAsynchronousWriteOperations
   print("is write? \(isWrite)") //outputs true
}

但是,在您的代码(缩写)中

var localRealm: Realm {
    get {
        return try! Realm()
    }
}
fileprivate func testAsyncRealm() {
    self.localRealm.beginAsyncWrite {
       let isWrite = self.localRealm.isPerformingAsynchronousWriteOperations
       print("is write? \(isWrite)") //outputs false
    }
}

输出为 false - 表明未设置该标志,因此 Realm 认为它不是异步写入。

我建议这种行为是因为每次通过

self.localRealm
访问 var 时,它都会重新初始化 Realm,并且该标志为 false。

简单的解决方案是使用同一 Realm 实例而不重新初始化它

fileprivate func doAsyncWrite() {
   var realm = self.localRealm  //gets a realm instance
        
   realm.beginAsyncWrite { //use that same realm to write, which sets the flag
      let isWrite = realm.isPerformingAsynchronousWriteOperations
      print("is write? \(isWrite)") //returns true
   }
}

进行此更改后,问题中的代码可以正常工作。


0
投票

您捕获了错误的异常,因为您尝试同时异步执行两个写入事务。他们的文档称您一次只需执行一笔交易。您可以通过几个选项来修复它:

  1. 每次交易后调用
    @escaping
    回调。
  2. 为您的领域对象编写
    @propertyWrapper
    并注入信号量并实现其逻辑,以避免同时进行多个工作事务。
  3. 如果由于 UI 故障您不想在串行队列上工作,那么在
    @propertyWrapper
    内部实现自己的并发队列并在该队列的包装器内实现所有逻辑是有意义的。

Realm 中的这些操作不是线程安全的原因是他们基本上避免“竞争条件”的想法。我们该如何处理它——这取决于我们。


只是他们的文档中关于

asynWrite<Result>(:)
的引用:

此功能与同步

write
的不同之处在于它会暂停 在等待轮到写入时调用任务而不是阻塞 线。此外,将数据写入磁盘的实际 I/O 是由 后台工作线程。对于小写入,在 主线程阻塞主线程的时间可能比手动阻塞的时间短 将写入分派到后台线程。

如果区块抛出错误,交易将被取消,任何 错误之前所做的更改将被回滚。

每个 Realm 文件一次只能打开一个写事务。写 事务不能嵌套,并且尝试在 已经处于写事务中的领域将抛出异常。 从其他中相同 Realm 文件的

write
实例调用
Realm
线程或其他进程将阻塞,直到当前写入事务 完成或取消。


干杯。

© www.soinside.com 2019 - 2024. All rights reserved.