我试图在后台线程上获取领域数据并添加通知块(iOS,Swift).
基本示例:
func initNotificationToken() {
DispatchQueue.global(qos: .background).async {
let realm = try! Realm()
results = self.getRealmResults()
notificationToken = results.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in
switch changes {
case .initial:
self?.initializeDataSource()
break
case .update(_, let deletions, let insertions, let modifications):
self?.updateDataSource(deletions: deletions, insertions: insertions, modifications: modifications)
break
case .error(let error):
fatalError("\(error)")
break
}
}
}
}
func initializeDataSource() {
// process the result set data
DispatchQueue.main.async(execute: { () -> Void in
// update UI
})
}
func updateDataSource(deletions: [Int], insertions: [Int], modifications: [Int]) {
// process the changes in the result set data
DispatchQueue.main.async(execute: { () -> Void in
// update UI
})
}
这样做我得到了
'Can only add notification blocks from within runloops'
我必须使用返回的数据进行更广泛的处理,并且只想在处理完成后更新UI时返回主线程.
另一种方法可能是在后台线程上进行任何更新后重新获取数据,然后进行处理,但感觉就像可以避免的开销一样.
有关解决此问题的最佳做法的任何建议?
要在后台线程上添加通知,您必须在该线程上手动运行运行循环,并从该运行循环的callout中添加通知:
class Stuff { var token: NotificationToken? = nil var notificationRunLoop: CFRunLoop? = nil func initNotificationToken() { DispatchQueue.global(qos: .background).async { // Capture a reference to the runloop so that we can stop running it later notificationRunLoop = CFRunLoopGetCurrent() CFRunLoopPerformBlock(notificationRunLoop, CFRunLoopMode.defaultMode.rawValue) { let realm = try! Realm() results = self.getRealmResults() // Add the notification from within a block executed by the // runloop so that Realm can verify that there is actually a // runloop running on the current thread token = results.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in // ... } } // Run the runloop on this thread until we tell it to stop CFRunLoopRun() } } deinit { token?.stop() if let runloop = notificationRunLoop { CFRunLoopStop(runloop) } } }
GCD不在其工作线程上使用运行循环,因此任何基于调度块到当前线程的运行循环(例如Realm的通知)的东西都不会被调用.为了避免让通知无声地无法做任何事情,Realm会尝试检查这一点,不幸的是,这需要令人窒息的PerformBlock舞蹈.