我试图在后台线程上获取领域数据并添加通知块(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 时返回主线程。
另一种方法可能是在后台线程上进行任何更新后重新获取数据,然后进行处理,但这感觉是可以避免的开销。
关于解决此问题的最佳实践有什么建议吗?
要在后台线程上添加通知,您必须在该线程上手动运行运行循环,并从该运行循环的标注中添加通知:
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 舞蹈。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)