Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How NotificationCenter#addObserver(forName:object:queue:using:) works?

I have a notification posted in the main thread, and I want to exec something in the background after I receiving that notification.

So I use this method with a background OperationQueue

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

I thought this should work, but it doesn't.

I have read about the doc, there are something I don't understand about the queue, it says:

queue
The operation queue to which block should be added.

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

so if we pass nil, the block will run synchronously on the posting thread, but what about if we pass a queue, does it still run synchronously on the posting thread?

I have wrote some code to test my thinking,

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()

the output was:

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

so the block does run synchronously on the posting thread.

My question was, what's the point of this method, and what's the point of the params queue, when should we use it?

like image 967
JIE WANG Avatar asked Nov 18 '25 00:11

JIE WANG


1 Answers

I added:

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")

This prints out:

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

We can tell it is running the using block in the OperationQueue queue.

My understanding is the NotificationCenter.post method will wait until the using block is complete (synchronously) regardless of what queue it runs the using block in. There is a NotificationQueue buffer class that gives the functionality you are looking for.

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")

Prints out:

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

I think the reason for the queue parameter is if using a serial queue for access control, one could pass in the queue to use. For example the UIKit uses the main queue to serialize all screen manipulation.You could do something like

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

So when you update your model from a background queue, you can post a notification to the controller to update the views, and guarantee the UIKit manipulation is done in the main queue.

like image 160
Popmedic Avatar answered Nov 20 '25 15:11

Popmedic



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!