简体   繁体   English

定期在Realm中保存对象

[英]Periodically save an object in Realm

I have a Realm object called Trip . 我有一个名为Trip的Realm对象。 It stores data of a user's movement. 它存储用户运动的数据。

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
}

In the view controller, I keep a class-level variable called trip . 在视图控制器中,我保留了一个名为trip的类级变量。

fileprivate var trip: Trip?

Whenever a user starts a trip, I initialize a Trip object and assigns it to this variable. 每当用户开始旅程时,我都会初始化一个Trip对象并将其分配给该变量。

trip = Trip()

And throughout the user's movements, I keep updating this trip object with the data. 在用户的整个移动过程中,我不断使用数据更新此trip对象。

I need to save this data to the Realm database every 1 minute. 我需要每1分钟将此数据保存到Realm数据库中。 So I run a timer. 所以我运行一个计时器。

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

Which executes a function to save this object in a background thread. 它执行一个功能将此对象保存在后台线程中。

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

    } catch {

    }
}

Up to here, it works fine. 到这里为止,一切正常。 The problem is after the first save, when I try to access that trip object again, it crashes with the following error. 问题是第一次保存后,当我尝试再次访问该trip对象时,它崩溃并显示以下错误。

libc++abi.dylib: terminating with uncaught exception of type realm::IncorrectThreadException: Realm accessed from incorrect thread. libc ++ abi.dylib:以类型为realm :: IncorrectThreadException的未捕获异常终止:从错误线程访问的领域。

I think this happens because I open a new Realm to save this object in a background thread. 我认为发生这种情况是因为我打开一个新的Realm将该对象保存在后台线程中。 I know that Realm isn't thread-safe. 我知道Realm不是线程安全的。

But I'm not sure how to resolve this. 但是我不确定如何解决这个问题。 How do I keep using the same trip object after saving it? 保存后,如何继续使用相同的trip对象?

To quote from Realm's documentation about Passing Instances Across Threads : 要引用Realm的文档中有关跨线程传递实例的信息

Instances of Realm , Results , or List , or managed instances of Object are thread-confined, meaning that they can only be used on the thread on which they were created, otherwise an exception is thrown. RealmResultsList实例或Object托管实例是线程限制的,这意味着它们只能在创建它们的线程上使用,否则会引发异常。

In your case, self.trip is a managed instance of an Object subclass, and you appear to be accessing it from both the main thread, and repeatedly from the serial dispatch queue you create within your save() method. 在您的情况下, self.tripObject子类的托管实例,您似乎同时从主线程和在save()方法中创建的串行分派队列中反复访问它。 It's important to keep in mind that the call to DispatchQueue.async will result in your code being executed on different threads depending on the whims of Grand Central Dispatch. 重要的是要记住,对DispatchQueue.async的调用将导致您的代码在不同线程上执行,具体取决于Grand Central Dispatch的想法。 That is to say that two consecutive calls like … 也就是说,两个连续的呼叫,例如……

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

… will often result in the work being performed on two different threads. ……通常会导致在两个不同线程上执行工作。

Realm's documentation on Passing Instances Across Threads contains an example of how to pass a thread-safe reference to an object across threads and resolve it in the Realm instance on the target thread. Realm关于跨线程传递实例的文档包含一个示例,该示例说明如何跨线程将线程安全引用传递给对象,并在目标线程上的Realm实例中解析该对象。

It's hard to provide a more specific suggestion in your case as I'm not clear what you're trying to do with your save() method and why you're calling it on a timer. 在您的情况下很难提供更具体的建议,因为我不清楚您要使用save()方法做什么以及为什么要在计时器上调用它的原因。 Managed Object instances (instances retrieved from a Realm, or that have already been added to a Realm) can only be modified within a write transaction, so any modifications to self.trip would need to be performed within the write transaction opened by your save() method for it to serve any purpose. 只能在写事务中修改托管Object实例(从Realm检索到的实例,或者已经添加到Realm的实例),因此对self.trip任何修改都需要在save()打开的写事务中执行save()以使其达到任何目的的方法。 For the pattern of using a timer to make sense you'd need to leave self.trip as an unmanaged object, at which point save() would update the Trip instance with the same ID in the Realm file. 对于使用计时器的方式,您需要将self.trip保留self.trip 托管对象,此时save()会使用Realm文件中的相同ID更新Trip实例。 To do this you'd want to use Realm.create(_:value:update:) instead of Realm.add(_:update:) , as create does not convert unmanaged instances to managed instances like add does. 为此,您需要使用Realm.create(_:value:update:)而不是Realm.add(_:update:) ,因为create不会像add那样将非托管实例转换为托管实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM