76

I found the following code snippet which allows NSNotification to be posted on the main thread from any background thread. I would like to know if this is a safe and acceptable practice please?

dispatch_async(dispatch_get_main_queue(),^{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"ImageRetrieved" 
                                                        object:nil 
                                                      userInfo:imageDict];
});
Alex Cio
  • 6,014
  • 5
  • 44
  • 74
RunLoop
  • 20,288
  • 21
  • 96
  • 151
  • Yes, this is safe and acceptable. Available in iOS 4.0 and later: https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/c/func/dispatch_async – Snowcrash Feb 03 '14 at 12:12

4 Answers4

66

Yes you can.

Generally you want the NSNotifications to be sent on the main , especially if they trigger UI activities like dismissing a modal login dialog.

Delivering Notifications To Particular Threads

Regular notification centers deliver notifications on the thread in which the notification was posted. Distributed notification centers deliver notifications on the main thread. At times, you may require notifications to be delivered on a particular thread that is determined by you instead of the notification center. For example, if an object running in a background thread is listening for notifications from the user interface, such as a window closing, you would like to receive the notifications in the background thread instead of the main thread. In these cases, you must capture the notifications as they are delivered on the default thread and redirect them to the appropriate thread.

Anoop Vaidya
  • 46,283
  • 15
  • 111
  • 140
  • 3
    The documentation for NSDistributedNotificationCenter contradicts this: "If the receiving process is multithreaded, do not depend on the notification arriving on the main thread. The notification is usually delivered to the main thread’s run loop, but other threads could also receive the notification." – Zoodle Von Noodleson Aug 26 '13 at 10:23
  • @zoom23: Even the extract I posted is from Apple Documentation. – Anoop Vaidya Aug 26 '13 at 12:46
  • I wonder why Apple's own notifications are delivered on arbitrary threads (ex. `ALAssetsLibraryChangedNotification`). Is it better practice to choose a thread on the receiver object? – Rivera Aug 18 '14 at 05:21
  • 5
    posting notifications on a specific thread is making assumptions about the client. I would post the notification and handle threading issues at the client – Matt Jun 15 '15 at 08:46
  • This has all changed since you can now choose the `OperationQueue` as I say below http://stackoverflow.com/a/42800900/8047 – Dan Rosenstark Mar 15 '17 at 04:12
17

Yes

This is - you are getting into the main thread and posting your notification. Can't get any safer than that.

Undo
  • 25,519
  • 37
  • 106
  • 129
  • 23
    But surely this is bad design, you cannot know what will handle your notification and therefore should not make assumptions about which thread it should be delivered on. The observer should handle the notification and make its own decision about which thread is appropriate. – Matt Jun 15 '15 at 08:47
  • @matt correct way to do it is on the subscriber's side. Which you can do for a while using `NotificationCenter` which is sometimes, even in the docs, called `NSNotificationCenter` – Dan Rosenstark Mar 15 '17 at 04:09
  • Wouldn't it be easy If we just add the mainQueue invocation to the selector method? @Matt, it this what you are pointing to? – nr5 May 30 '19 at 09:13
15

YES

Swift 2 syntax

dispatch_async(dispatch_get_main_queue()) {
    NSNotificationCenter.defaultCenter().postNotificationName("updateSpinner", object: nil, userInfo: ["percent":15])
}

Swift 3 syntax

DispatchQueue.main.async {
    NotificationCenter.default.post(name: "updateSpinner", object: nil, userInfo: ["percent":15])
}
pableiros
  • 14,932
  • 12
  • 99
  • 105
WhipsterCZ
  • 638
  • 1
  • 8
  • 13
13

Somewhere along the line this became possible with:

addObserver(forName:object:queue:using:)

which is here, but the whole point is the queue object.

The operation queue to which block should be added. If you pass nil, the block is run synchronously on the posting thread.

So how do you get the queue that corresponds to the main runloop?

let mainQueue = OperationQueue.main

Note: this is when you are subscribing to notifications, so you do it once and you're done. Doing it on every single call is terribly redundant.

Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421