我最近开始使用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从错误的线程访问。
我理解我必须为每个线程使用领域,我可以通过在主线程上读取领域来实现这一点,但我不希望领域查询阻止我的主线程。
有什么方法可以实现我的目标吗?例如在后台队列中读取域并从另一个线程访问结果,同时保持自动刷新功能。
感谢。
答案 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