我们可以在后台队列中生成Realm结果并在主线程

时间:2018-01-07 03:33:55

标签: ios swift realm

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

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

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

    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,我会收到类似

的错误
  

由于未捕获的异常终止应用程序&#39; RLMException&#39;,原因:&#39; Realm从错误的线程访问。

我理解我必须为每个线程使用领域,我可以通过在主线程上读取领域来实现这一点,但我不希望领域查询阻止我的主线程。

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

感谢。

4 个答案:

答案 0 :(得分:3)

Realm具有内置功能,可以在后台线程上运行查询,并使用Results.observe()将结果传递给主线程。

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

答案 1 :(得分:1)

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

正如本GitHub问题https://github.com/realm/realm-cocoa/issues/946中所提到的,建议的做法是共享主键(如果你的领域对象覆盖了RealmObject(Objective-C)/ Object(Swift)的primaryKey方法)。

答案 2 :(得分:0)

您正试图直接访问&#39;结果&#39;来自不同队列的属性将崩溃。您应该使用ThreadSafeReference,如Thomas的答案所示。

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

答案 3 :(得分:0)

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

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

这是在iPhone X上的结果,该数据库具有约17.1万个项目。持续时间以秒为单位。

在用户界面界面上搜索:

UI thread blocked 0.730504035949707

从上面的代码中搜索:

UI thread blocked 0.28138411045074463
background search duration 0.5073530673980713