簡體   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