首页 文章

定期在Realm中保存对象

提问于
浏览
0

我有一个名为 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 回答

  • 1

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

    Realm,Results或List的实例或Object的托管实例是线程限制的,这意味着它们只能在创建它们的线程上使用,否则会引发异常 .

    在您的情况下, self.tripObject 子类的托管实例,您似乎是从主线程中访问它,并且是从您在 save() 方法中创建的串行调度队列中重复访问它 . 重要的是要记住,对 DispatchQueue.async 的调用将导致您的代码在不同的线程上执行,具体取决于Grand Central Dispatch的一时兴起 . 也就是说连续两次打电话......

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

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

    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 .

相关问题