繁体   English   中英

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

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

我最近开始使用 Realm,我不确定我的用例是否有效:

通常,当从数据库读取大量数据时,我想将其放入后台队列,以便异步获取数据,然后在主线程上使用它。

例如,我想根据城市获取多个结果:

    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")
            }
        }
    }

稍后使用results更新我的图表:

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

但是,如果我将此模型应用于 Realm,则会出现类似错误

由于未捕获的异常“RLMException”而终止应用程序,原因:“从不正确的线程访问的领域。

我知道我必须为每个线程使用领域,我可以通过在主线程上读取领域来做到这一点,但我不希望领域查询阻塞我的主线程。

有什么办法可以实现我的目标吗? 例如,在后台队列中读取领域并从另一个线程访问结果,同时保持自动刷新功能。

谢谢。

Realm 具有在后台线程上运行查询并使用Results.observe()将结果传送到主线程的内置功能。

如果您特别需要执行无法表示为 Realm 查询的昂贵过滤逻辑,您可以使用ThreadSafeReference在线程之间手动传递对象数组。

从 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
    }
}

领域对象只能通过从中获取或创建它们的领域访问。 领域实例不能在线程(您知道)之间共享,并且从特定领域实例向另一个线程共享对象,隐式地具有与线程之间共享领域实例相同的效果。 这是由于对象和领域实例之间的紧密耦合。

正如此 GitHub 问题https://github.com/realm/realm-cocoa/issues/946中所述,推荐的做法是共享主键(如果您的领域对象覆盖 RealmObject (Objective-C) /对象(Swift))。

您正在尝试从不同的队列直接访问“结果”属性,这会崩溃。 您应该改为使用 ThreadSafeReference,如 Thomas 的回答所示。

在从 Realm 数据库获取之前,请确保为结果创建一个 ThreadSafeReference 并在后台队列上调用 realm.resolve() 。

我是这样解决的。 我看到了整体性能改进,但我找不到任何用于在后台线程上查询的实现示例。 可能有一个性能更好的解决方案。

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

这是在 iPhone X 上的结果,数据库包含约 171k 项。 持续时间以秒为单位。

在用户界面上搜索:

UI thread blocked 0.730504035949707

使用上面的代码搜索:

UI thread blocked 0.28138411045074463
background search duration 0.5073530673980713

暂无
暂无

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

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