【问题标题】:Periodically save an object in Realm定期在 Realm 中保存对象
【发布时间】:2017-08-19 15:03:46
【问题描述】:

我有一个名为Trip 的领域对象。它存储用户移动的数据。

class Trip: Object {
    dynamic var id: Int = 0
    dynamic var startTimestamp: Int64 = 0
    dynamic var endTimestamp: Int64 = 0
    dynamic var distance: Double = 0.0
    dynamic var calories: Double = 0.0
    dynamic var averageSpeed: Double = 0.0
}

在视图控制器中,我保留了一个名为 trip 的类级变量。

fileprivate var trip: Trip?

每当用户开始旅行时,我都会初始化一个Trip 对象并将其分配给该变量。

trip = Trip()

在用户的移动过程中,我不断用数据更新这个trip 对象。

我需要每 1 分钟将这些数据保存到 Realm 数据库中。所以我运行了一个计时器。

Timer.scheduledTimer(timeInterval: 60, target: self, selector: #selector(save()), userInfo: nil, repeats: true)

它执行一个函数将这个对象保存在后台线程中。

fileprivate func save() {
    do {
        DispatchQueue(label: "RealmBackgroundThread").async {
            autoreleasepool {
                let realm = try! Realm()
                try! realm.write {
                    realm.add(self.trip!, update: true)
                }
            }
        }

    } catch {

    }
}

到这里为止,一切正常。问题是在第一次保存后,当我再次尝试访问该trip 对象时,它会崩溃并出现以下错误。

libc++abi.dylib: 以未捕获的领域类型异常终止::IncorrectThreadException: 领域从不正确的线程访问。

我认为这是因为我打开了一个新的Realm 以将此对象保存在后台线程中。我知道 Realm 不是线程安全的。

但我不确定如何解决这个问题。保存后如何继续使用相同的trip 对象?

【问题讨论】:

标签: ios swift multithreading realm


【解决方案1】:

引用 Realm 关于Passing Instances Across Threads 的文档:

RealmResultsList 的实例或Object 的托管实例是线程受限的,这意味着它们只能在创建它们的线程上使用,否则会出现异常扔了。

在您的情况下,self.tripObject 子类的托管实例,您似乎正在从主线程访问它,并且从您在 save() 方法中创建的串行调度队列中重复访问它。请务必记住,对DispatchQueue.async 的调用将导致您的代码在不同的线程 上执行,具体取决于 Grand Central Dispatch 的突发奇想。也就是说,连续两次调用像……

DispatchQueue(label: "RealmBackgroundThread").async {
    // work
}

... 通常会导致工作在两个不同的线程上执行。

Realm 关于Passing Instances Across Threads 的文档包含一个示例,说明如何跨线程传递对对象的线程安全引用并在目标线程上的Realm 实例中解析它。

很难就您的情况提供更具体的建议,因为我不清楚您要使用 save() 方法做什么以及为什么要在计时器上调用它。托管 Object 实例(从领域检索的实例,或已添加到领域的实例)只能在写入事务中修改,因此对 self.trip 的任何修改都需要在您打开的写入事务中执行save() 用于任何目的的方法。为了使使用计时器的模式有意义,您需要将 self.trip 保留为 unmanaged 对象,此时 save() 将更新具有相同 ID 的 Trip 实例领域文件。为此,您需要使用Realm.create(_:value:update:) 而不是Realm.add(_:update:),因为create 不会像add 那样将非托管实例转换为托管实例。

【讨论】:

  • 谢谢。使用Realm.create(_:value:update:) 有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-25
  • 1970-01-01
相关资源
最近更新 更多