简体   繁体   English

我们可以在后台队列中生成 Realm 结果并在主线程上使用它吗

[英]Can we generate Realm results in background queue and use it on main thread

I'm starting using Realm recently, I'm not sure if my use case is valid:我最近开始使用 Realm,我不确定我的用例是否有效:

Normally, when reading a lot of data from DB, I want to put it in a background queue so it will async get the data and later use it on main thread.通常,当从数据库读取大量数据时,我想将其放入后台队列,以便异步获取数据,然后在主线程上使用它。

For example, I want to fetch several results based on city:例如,我想根据城市获取多个结果:

    private var results: [Results<SomeObject>?] = []
    autoreleasepool {
        DispatchQueue(label: "background").async {
            [unowned self] in
            do
            {
                let realm = try Realm()
                for i in 1...City.count
                {
                    self.results.append(realm.objects(SomeObject.self).filter("city=\(i)"))
                }
            }
            catch
            {
                NSLog("Failed to open Realm instance on background qeueue")
            }
        }
    }

And later use results to update my chart:稍后使用results更新我的图表:

cell.setChartData(ChartDataFactory.createCombinedData(from: results[0]))

However if I apply this model for Realm, I'm getting error like但是,如果我将此模型应用于 Realm,则会出现类似错误

Terminating app due to uncaught exception 'RLMException', reason: 'Realm accessed from incorrect thread.由于未捕获的异常“RLMException”而终止应用程序,原因:“从不正确的线程访问的领域。

I understand I must use realm for each thread, and I can do this by reading realm on main thread, but I don't want the realm query block my main thread.我知道我必须为每个线程使用领域,我可以通过在主线程上读取领域来做到这一点,但我不希望领域查询阻塞我的主线程。

is there any way I can achieve my goal?有什么办法可以实现我的目标吗? eg reading realm in a background queue and access the results from another thread, while keeping the auto-refresh feature.例如,在后台队列中读取领域并从另一个线程访问结果,同时保持自动刷新功能。

Thanks.谢谢。

Realm has built-in functionality for running a query on a background thread and delivering the results to the main thread by using Results.observe() . Realm 具有在后台线程上运行查询并使用Results.observe()将结果传送到主线程的内置功能。

If you specifically need to perform expensive filtering logic that can't be expressed as a Realm query, you can manually pass an array of objects between threads using ThreadSafeReference .如果您特别需要执行无法表示为 Realm 查询的昂贵过滤逻辑,您可以使用ThreadSafeReference在线程之间手动传递对象数组。

As of 5.0, you can now construct the query on a background thread and receive notifications on the main thread using the on: parameter to observe() :从 5.0 开始,您现在可以在后台线程上构造查询,并使用on:参数来observe()在主线程上接收通知:

DispatchQueue.global().async {
    let realm = try! Realm()
    let results = realm.objects(ObjectType.self).filter("property in %@", expensiveFunction(realm))
    self.token = results.observe(on: .main) { change in
        // do stuff with the results on the main thread
    }
}

Realm objects are only accessible through the realm from which they are fetched or created.领域对象只能通过从中获取或创建它们的领域访问。 Realm instances cannot be shared between threads (which you are aware of), and sharing an object from a specific realm instance to another thread, implicitly has the same effects as sharing a realm instance between threads.领域实例不能在线程(您知道)之间共享,并且从特定领域实例向另一个线程共享对象,隐式地具有与线程之间共享领域实例相同的效果。 This is due to the tight coupling between the objects and the realm instance.这是由于对象和领域实例之间的紧密耦合。

As mentioned in this GitHub issue https://github.com/realm/realm-cocoa/issues/946 , the recommended practice is to share the primary keys (if your realm object overrides the primaryKey method of RealmObject (Objective-C) / Object (Swift)).正如此 GitHub 问题https://github.com/realm/realm-cocoa/issues/946中所述,推荐的做法是共享主键(如果您的领域对象覆盖 RealmObject (Objective-C) /对象(Swift))。

You're trying to directly access 'results' property from a different queue and that will crash.您正在尝试从不同的队列直接访问“结果”属性,这会崩溃。 You should instead use ThreadSafeReference as indicated on the answer of Thomas.您应该改为使用 ThreadSafeReference,如 Thomas 的回答所示。

Make sure to create a ThreadSafeReference for results and call realm.resolve() on your background queue before fetching from your Realm database.在从 Realm 数据库获取之前,请确保为结果创建一个 ThreadSafeReference 并在后台队列上调用 realm.resolve() 。

I solved it like this.我是这样解决的。 I see an overall performance improvement, but I couldn't find any implementation example for querying on a background thread.我看到了整体性能改进,但我找不到任何用于在后台线程上查询的实现示例。 Might be there is a solution with even better performance.可能有一个性能更好的解决方案。

self.results = self.realm.objects(Object.self).filter(predicate).sorted(by: sortProperties)
self.notificationToken = self.results.observe({ (notification) in
    self.tableview.reloadData()
})

This is the results on an iPhone X with a database of ~171k items.这是在 iPhone X 上的结果,数据库包含约 171k 项。 Durations are in seconds.持续时间以秒为单位。

Search on UI tread:在用户界面上搜索:

UI thread blocked 0.730504035949707

Search with the code from above:使用上面的代码搜索:

UI thread blocked 0.28138411045074463
background search duration 0.5073530673980713

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

相关问题 如何获取后台队列中对象的Realm结果,然后在主线程上使用它 - How get Realm result of objects in background queue, then use it on main thread CoreData - 无论主线程还是后台线程,我们都可以始终使用 backgroundContext 吗? - CoreData - Can we always use backgroundContext regardless of main or background thread? 在主线程中使用后台线程的快速领域插入数组 - swift realm insert array in background thread use in main 领域:从后台线程进行添加,更新,删除操作并在主线程上获取结果的正确方法 - Realm: the right way to make add,update,remove operations from background thread and get results on the main thread 我们可以将后台线程操作更改为主线程吗? - can we change a background thread operation to main thread? 在后台线程上删除Realm对象会阻塞主线程 - Deleting Realm objects on a background thread blocks the main thread 领域在后台线程上获取对象并传递给主线程 - Realm fetching objects on background thread and pass to main thread 调度到并发队列导致在主线程上执行? - Dispatch to concurrent queue results in execution on main thread? 结果来自主线程,而不是后台线程 - Results coming on main thread, but not on background thread 我们需要在主线程或主队列中更新UI吗? - Do we need to update UI in main thread or in main queue?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM