[英]Periodically save an object in Realm
我有一个名为Trip
的Realm对象。 它存储用户运动的数据。
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:以类型为realm :: IncorrectThreadException的未捕获异常终止:从错误线程访问的领域。
我认为发生这种情况是因为我打开一个新的Realm
将该对象保存在后台线程中。 我知道Realm不是线程安全的。
但是我不确定如何解决这个问题。 保存后,如何继续使用相同的trip
对象?
要引用Realm的文档中有关跨线程传递实例的信息 :
Realm
,Results
或List
实例或Object
托管实例是线程限制的,这意味着它们只能在创建它们的线程上使用,否则会引发异常。
在您的情况下, self.trip
是Object
子类的托管实例,您似乎同时从主线程和在save()
方法中创建的串行分派队列中反复访问它。 重要的是要记住,对DispatchQueue.async
的调用将导致您的代码在不同线程上执行,具体取决于Grand Central Dispatch的想法。 也就是说,两个连续的呼叫,例如……
DispatchQueue(label: "RealmBackgroundThread").async {
// work
}
……通常会导致在两个不同线程上执行工作。
Realm关于跨线程传递实例的文档包含一个示例,该示例说明如何跨线程将线程安全引用传递给对象,并在目标线程上的Realm
实例中解析该对象。
在您的情况下很难提供更具体的建议,因为我不清楚您要使用save()
方法做什么以及为什么要在计时器上调用它的原因。 只能在写事务中修改托管Object
实例(从Realm检索到的实例,或者已经添加到Realm的实例),因此对self.trip
任何修改都需要在save()
打开的写事务中执行save()
以使其达到任何目的的方法。 对于使用计时器的方式,您需要将self.trip
保留self.trip
托管对象,此时save()
会使用Realm文件中的相同ID更新Trip
实例。 为此,您需要使用Realm.create(_:value:update:)
而不是Realm.add(_:update:)
,因为create
不会像add
那样将非托管实例转换为托管实例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.