NotificationCenter#addObserver(forName:object:queue:using :)如何工作?

时间:2019-07-12 13:40:39

标签: ios swift nsnotificationcenter

我在主线程中发布了一条通知,我希望在收到该通知后在后台执行某些操作。

所以我将此方法与背景OperationQueue一起使用

func addObserver(forName name: NSNotification.Name?, 
          object obj: Any?, 
           queue: OperationQueue?, 
           using block: @escaping (Notification) -> Void) -> NSObjectProtocol

我认为这应该可以,但是不能。

我已经读过有关doc的内容,但我对队列不了解,它说:

queue
The operation queue to which block should be added.

If you pass nil, the block is run synchronously on the posting thread.

因此,如果我们通过nil,该块将在发布线程上同步运行,但是如果我们通过queue,它仍会同步运行在发布线程上?

我已经写了一些代码来测试我的想法,

import Foundation

let queue = OperationQueue()
let testNotification = Notification.Name("testNotification")

NotificationCenter.default.addObserver(forName: testNotification, object: nil, queue: queue) { _ in
    print("receive notification: before sleep.")
    Thread.sleep(forTimeInterval: 2)
    print("receive notification: after sleep.")
}

NotificationCenter.default.post(name: testNotification, object: nil)

print("main thread")
RunLoop.main.run()

输出为:

receive notification: before sleep.
receive notification: after sleep.
main thread

因此该阻止确实在发布线程上同步运行。

我的问题是,此方法的意义是什么,参数queue的意义是什么,我们什么时候应该使用它?

1 个答案:

答案 0 :(得分:0)

我添加了:

import Foundation

let queue = OperationQueue()
let testNotification = Notification.Name("testNotification")

NotificationCenter.default.addObserver(forName: testNotification, object: nil,
                                       queue: queue) { _ in

    if queue == OperationQueue.current { print("I am in my queue") }

    print("receive notification: before sleep.")
    Thread.sleep(forTimeInterval: 2)
    print("receive notification: after sleep.")
}

NotificationCenter.default.post(name: testNotification, object: nil)

print("main thread")

打印输出:

I am in my queue
receive notification: before sleep.
receive notification: after sleep.
main thread

我们可以知道它正在运行OperationQueue using中的queue块。

我的理解是,无论NotificationCenter.post块在哪个队列中运行,using方法都会一直等到using块完成(同步)为止。有一个NotificationQueue缓冲区类可提供您正在寻找的功能。

NotificationCenter.default.addObserver(forName: testNotification, object: nil,
                                       queue: queue) { _ in

    print("receive notification: before sleep.")
    Thread.sleep(forTimeInterval: 2)
    print("receive notification: after sleep.")
}

NotificationQueue.default.enqueue(Notification(name: testNotification),
                                  postingStyle: .whenIdle)

print("main thread")

打印出:

main thread
receive notification: before sleep.
receive notification: after sleep.

我认为使用queue参数的原因是,如果使用串行队列进行访问控制,则可以传递queue来使用。例如,UIKit使用main队列来序列化所有屏幕操作。您可以执行类似的操作

NotificationCenter.default.addObserver(forName: testNotification, object: nil,
                                       queue: OperationQueue.main) { _ in
    // Do a bunch of UI stuff
}

因此,当您从后台队列更新模型时,可以向控制器发布通知以更新视图,并确保UIKit操作在main队列中完成。