我有一个名为 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 {
}
}
到这里,它工作正常 . 问题是在第一次保存后,当我再次尝试访问该对象时,它崩溃并出现以下错误 .
libc abi.dylib:以类型为realm的未捕获异常终止:: IncorrectThreadException:从错误的线程访问的Realm .
我认为这是因为我打开一个新的 Realm
以在后台线程中保存此对象 . 我知道Realm不是线程安全的 .
但我不知道如何解决这个问题 . 保存后如何继续使用相同的 trip
对象?
1 回答
引用Realm关于Passing Instances Across Threads的文档:
在您的情况下,
self.trip
是Object
子类的托管实例,您似乎是从主线程中访问它,并且是从您在save()
方法中创建的串行调度队列中重复访问它 . 重要的是要记住,对DispatchQueue.async
的调用将导致您的代码在不同的线程上执行,具体取决于Grand Central Dispatch的一时兴起 . 也就是说连续两次打电话.........通常会导致在两个不同的线程上执行工作 .
Realm在Passing Instances Across Threads上的文档包含一个示例,说明如何跨线程传递对象的线程安全引用,并在目标线程的
Realm
实例中解析它 .它's hard to provide a more specific suggestion in your case as I'我不清楚你想用你的
save()
方法做什么以及为什么你在计时器上调用它 . 托管Object
实例(从Realm检索的实例,或已经添加到Realm的实例)只能在写入事务中修改,因此需要在save()
方法为其启动的写入事务中执行对self.trip
的任何修改为任何目的服务 . 对于使用计时器有意义的模式,您需要将self.trip
保留为非托管对象,此时save()
将使用Realm文件中的相同ID更新Trip
实例 . 要执行此操作,您需要使用Realm.create(_:value:update:)
而不是Realm.add(_:update:)
,因为create
不会将非托管实例转换为托管实例,如add
.