当前位置:  开发笔记 > 编程语言 > 正文

领域通知令牌在背景线程上

如何解决《领域通知令牌在背景线程上》经验,为你挑选了1个好方法。

我试图在后台线程上获取领域数据并添加通知块(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时返回主线程.

另一种方法可能是在后台线程上进行任何更新后重新获取数据,然后进行处理,但感觉就像可以避免的开销一样.

有关解决此问题的最佳做法的任何建议?



1> Thomas Goyne..:

要在后台线程上添加通知,您必须在该线程上手动运行运行循环,并从该运行循环的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舞蹈.

推荐阅读
郑谊099_448
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有