Fundamentals of NSNotificationCenter in Swift

Updated on September 19, 2016 – Xcode 8 & Swift 3.0

The goal of this post is to help you grasp the fundamentals of using NSNotificationCenter in your Swift iOS app. The topic isn’t necessarily new, and there’s no difference except syntax between Objective-C and Swift implementations involving NSNotificationCenter. Even still, I’m hoping to add to the understanding of this useful tool by giving a fully-working example on GitHub (Swift 2.3 and Swift 3.0), and by sharing the insight that’s clicked in my own brain as I explain the example.

Note: Code in the main article below is written in Swift 3.0, but code examples for Swift 2.3 are found in the example project.

First things first: What is this thing?

When I first heard NSNotificationCenter, I thought “push notifications”. However, NSNotificationCenter has nothing to do with sending or receiving push notifications in iOS. Rather, it is a communication tool internal to your app. It provides a way for one instance of a class/struct to notify one or more other class/struct instances about something. The goal in doing this is to enable those 1+ other class or struct instances to take appropriate action based the communication they receive. An common analogy comes to mind: think “radio tower”. NSNotificationCenter is the central hub that acts as a broadcaster of notifications. If that still seems vague, hang tight – seeing the example below should help it all come together for you.

Should I use it?

Before diving into the basic workflow, it’s worth asking, “Should I use NSNotificationCenter, or is there some other option that’s more appropriate for my app’s internal communication needs?”

It is often the case that there is more than one way to solve a problem in software development, and it’s no different with NSNotificationCenter. There is more than one way to accomplish instance-to-instance communication at run-time. I’ve written about two such forms of communication in my post titled NSNotificationCenter vs Delegation – An Analysis. It may be worth reading up on, just to make sure you’re using the right tool for the right kind of communication.

Basic Workflow

NSNotificationCenter.default is at the center of it all when it comes to this discussion.

The basic workflow of using NSNotificationCenter goes something like this:

  1. Since NSNotificationCenter is in the business of broadcasting notifications, the first thing to do is to specify a way to uniquely identify a notification. This is most easily accomplished by defining a constant string value (using let syntax in Swift) at a globally-visible scope. The string constant you define here will serve as a “notification key”. If you have several notification keys that you need to define, perhaps creating a new .swift file called “NSNotificationCenterKeys.swift” is a clean way to do this.
  2. Steps 2 and 3 of the workflow go hand-in-hand. Without implementing the one, implementing the other doesn’t make much sense… Step 2 is to post a notification to NSNotificationCenter.default identified by the key that was created in step 1. In radio terms, the class or struct instance desiring to post a notification asks the default notification center to broadcast the notification key defined in step 1… this class or struct instance chooses the right situations to request that the notification key be sent out based on business logic specific to the project’s requirements.
  3. Step 3 is to set up 1+ class or struct instances to be listeners, or more properly, observers of a particular notification. Such an observer will be able to tell that it’s “heard” the notification, because it will be “listening for” a notification that uses the same key that was created in step 1, which is the key used in step 2 to post the notification. In radio terms, the listener is tuned in to the default notification center’s station that’s identified by that special key defined in step 1 and posted in step 2. So you see now why steps 2 and 3 go hand-in-hand. With no posts to the notification center on that station, tuning in will do no good. Likewise, posting a notification but having no listeners accomplishes nothing.
  4. Finally, what should the observing instance do once it’s detected the notification? Well, when signing up to be an observer, the instance must also specify the name of a function that will be called upon receipt of the notification it’s listening for. Whatever action or routine is appropriate to perform at that time is what that function’s implementation should contain.

Visualizing NSNotificationCenter by Example

If you’re like me, you need less talk and more example, so I’ve created a simple XCode project that you can grab over at GitHub (Swift 2.3 and Swift 3.0). Running the project will allow you to click through a series of tabs in a tab view controller, post a notification, and see the results. It looks much like this:

NS Notification Center Example

Working back through the basic workflow with this example you can find the following key aspects of implementing a NSNotificationCenter solution (lines of code to pay special attention to will be highlighted).

Steps 1 and 2:

I’ve chosen my FirstViewController class to be the one that defines the global constant with a unique notification key and tells the default notification center to post that notification when the “Notify!” button is tapped:

Steps 3 and 4:

Both of these steps are implemented in very similar ways in my SecondViewController and ThirdViewController classes. The code should speak for itself:

Finally, to reiterate the explanation in visual form and for easy reference, I’ve annotated a screen shot taken from the project’s code:

NSNotificationCenter Explanation

Removing an observer

One final requirement for working with NSNotificationCenter is to remove an observer when it no longer needs to listen for notifications. When might this situation arise?

  • When the observer is no longer referenced and thus deallocated from memory, it should tell the default notification center that it can be removed
  • When some condition occurs in your application that renders it no longer relevant for an instance to listen for notifications

The first situation is the most common, and is for sure the scenario that we want to protect against, so that the default notification center doesn’t continue to manage observers that are no longer capable of actively listening. To satisfy the requirement of removing an observer when an instance is deallocated, we could provide something like the following deinit method:

For the second bullet point, you can simply write the same line of code that’s highlighted in the above snippet, wherever it makes sense for you to tell the default notification center when it’s appropriate to stop sending messages to the instance in question.

Summary

NSNotificationCenter is particularly useful when there are multiple class or struct instances that need to take action based on something that happens elsewhere in your application. For this type of scenario, NSNotificationCenter can be a great tool to wield as you develop apps in Swift for iOS.

  • Thanks, this was very helpful!

  • Thanks, this was very helpful!

  • Pingback: core data & cloud services for iOS in Swift | Anaara Blog()

  • Pingback: core data & cloud services for iOS in Swift | Anaara Blog()

  • Matias Araujo

    Thanks This was very helpful, i only have one doubt when and where i should remove the observers?

  • Matias Araujo

    Thanks This was very helpful, i only have one doubt when and where i should remove the observers?

  • Jim

    Been searching the net for a clear, concise explanation of this. Happened upon this and I am grateful. Thanks!

    • Andrew Bancroft

      Very cool – thanks for that encouragement, Jim.

  • MiGi

    Than You for this tutorial. Can I pass some data with this method? Let’s say I have variable in FirstViewController and I want to pass it to SecondViewController. How can I do that?

  • MiGi

    Ok, I know how to pass data but I have one question left. How to make your tutorial to work without necessity to visit each tab first?

    • Andrew Bancroft

      Hi MiGi,

      Glad you figured out how to pass data – Your asking means I probably need to cover that at some point though. Perhaps a new blog post is coming on that subject, but again – glad you’re good to go on it for now. :]

      It’s interesting you pointed out the necessity of visiting each tab first. The reason it doesn’t work unless you visit each tab first is because those view controllers that control each tab don’t exist in memory (and thus can’t listen for notifications) until they’re visited. I don’t really see a way around that, unfortunately.

      NSNotificationCenter is great if there are listeners for its notifications, but if a controller or other object doesn’t exist yet, it obviously can’t receive messages… I don’t suppose a non-existent thing would care though.

      I’d use NSNotificationCenter in such a way as to say, “I’m going to broadcast these messages, and if there are listeners, they can respond how they need to, but I’m not going to count on any listeners being present.” I’ve heard it said that NSNotificationCenter is meant for very loose / weak interactions between controllers. To be sure, you’d need to make sure whatever listener controllers that need the notifications are initialized already. Otherwise, broadcasting the notifications has no effect.

      If you need a more structured environment around your controller-to-controller communication, delegates and callbacks are probably a better choice.

      • MiGi

        I found a solution:) Register your second and third controller in initialiser instead of viewDidLoad. Anyway, thank you for this tutorial, you helped me a lot.

        • Andrew Bancroft

          Awesome! Yeah, registering for notifications in the initializer makes sense. Good find – I learned something today! :]

          Very glad the post helped you.

      • Ag

        Great clear and concise tutorial… I just have a question regarding your last comment: “If you need a more structured environment around your controller-to-controller communication, delegates and callbacks are probably a better choice.”… would you be able to elaborate on this part? I would really appreciate any info on how to implement this using delegates and callbacks…

        Thanks a lot! and keep up the great blog!

        • Andrew Bancroft

          Sorry for the delayed response – I promise I haven’t been ignoring this reply. I’m thinking I need to write a blog post about this, but I’m not sure when I can get it into my queue. It may be a couple of weeks, but I’d like to give this some thought and attention. Thanks a ton for asking for this clarification!

          • Ag

            no worries, looking forward to your blog post 🙂

        • Andrew Bancroft

          Ag – I did my best to elaborate and do a little analysis in my latest post: http://www.andrewcbancroft.com/2015/02/05/nsnotificationcenter-vs-delegation-analysis/

          I hope it’s no too late and provides some insight into what I was thinking when I wrote the comment you referenced.

          • Ag

            Thanks! I saw it, I just added a comment to it. It took me a lil while to consider it but I hope you’re able to answer the next question 🙂

            Thanks again!

  • castletrader

    Thanks! Awesome tutorial

  • Pingback: NSNotificationCenter vs Delegation - A Swift Analysis - Andrew Bancroft()

  • yaron levi

    Thanks ! helped me a lot.
    But there one thing I think you should fix.
    The selector “actOnSpecialNotification” should contain a colon like so “actOnSpecialNotification:”
    For me it worked.

    • Andrew Bancroft

      I’m thinking this is only required if you desire to pass along data _with_ the notification. In that situation, the function we specify in the addObserver() method would take a parameter, which is when the colon would be required.

      Are you observing different behavior?

  • Matt Hoffman

    Hi Andrew, I used this tutorial to integrate NSNotificationCenter into my app and it was very helpful. However, because this was my introduction to NSNotificationCenter, I had no idea that you also had to remove the observers after you finished with them. I think it would be helpful if you included a brief note on that at the end. For anyone who needs it, the call is: NSNotificationCenter.defaultCenter().removeObserver(self)

    • Andrew Bancroft

      Excellent point, Matt! My plan is to update the post with this information as I cycle back around to make other improvements. I appreciate you bringing it up because you’re right – removing the observer of a notification is a necessary step.

      • Amitai Blickstein

        …but not anymore!

        Apple Docs:
        >If your app targets iOS 9.0 and later or OS X v10.11 and later, you don’t need to unregister an observer in its deallocation method. If your app targets earlier releases, be sure to invoke removeObserver(_:name:object:) before observer or any object specified in addObserver:selector:name:object: is deallocated.

    • Andrew Bancroft

      Hey Matt – I updated the post just now to incorporate your suggestion. Take a look at https://www.andrewcbancroft.com/2014/10/08/fundamentals-of-nsnotificationcenter-in-swift/#remove-observer and let me know if it could use any more clarification. Thank you again for your feedback!

  • extendsprite

    Perfect tutorial. I am always using designs like that in my other coding language project. So when i first start to ios i quickly dive into search structures like NSNotificationCenter. As you said there are many ways to communicate instance also they are exist in ios but these type of usage i am pretty sure is the mother of this creature. So think a lot what you are need according to what you want to build. I love that but i wonder something maybe you can give me a valid answer. If there will be no observer after removing them from the center, their special connection key(your advice) commonly name and selector data also will be removed from the center? I think it should be because if there is no observer in the observer list there is no need to keep the keys that related with these observers. Thank you…

    • Andrew Bancroft

      Thanks for your comment!

      So NSNotificationCenter keeps a “dispatch table” of all observers registered to be notified when a given key is “posted” to. When removeObserver is called, it removes all entries in that dispatch table related to the observer you specify.

      Apple Docs:
      removeObserver:
      “Removes all the entries specifying a given observer from the receiver’s dispatch table.”

      As for the key itself, I placed it in a global constant to avoid having to re-type it as I added observers for that key throughout my code. The moment I typed it twice, I refactored it into a shareable constant. Technically you only need the key for registering or removing specific observers for that specific notification key, but to avoid re-typing it and risking making a typo in your code, it’s probably a good idea to keep it stored as a constant somewhere.

      I may be misunderstanding your question though – did that answer it, or were you aiming for a different answer?

      • extendsprite

        Yes i understand all at the first part of your answer. Thank you…

  • Anh Dũng Trương

    Hi Andrew, I have an issue that checking an other application installed in device. When an application, that have package name, have been installed in device, how can I listen this event, by using NSNotification?

  • Pingback: Fundamentals of Callbacks for Swift Developers - Andrew Bancroft()

  • abhishek

    Thanx. Awesome tutorial! I need a bit of help. I am making an app which user can use online as well as offline ( as in not connected to internet ). What I want to do is if the user is online and does some changes in the app, i want to ping my corresponding api whenever he/she is online. Like in ‘whatsapp’. If you are offline and send a message it gets scheduled. Whenever the device is online, the updation is automatically done. How to do it in swift?

    • Andrew Bancroft

      For this one, it’s less about NSNotificationCenter and more about the concept of “Reachability”. You may or may not want to bring in a 3rd party library for this, but if interests you, I believe Alamofire, a Swift networking library available on GitHub, includes a class that assists in detecting whether or not an internet connection is present on the device or not. You could then implement the logic to schedule the message or make the actual API request, depending on that internet connection status.

      The URL for Alamofire on GitHub is https://github.com/Alamofire/Alamofire/tree/e3ab8fccb2a56924167ae09c94dea03768bbff73 .

  • Sergio Aguiar

    Thank you for the tutorial.

    I am working in a project where I need to authenticate an user using a webservice and json.
    I call the connection and need to wait for the result to return to my main class but allways the class returns before the http service finish, so the result is allways null.

    this is the code I am using:

    let task = NSURLSession.sharedSession().dataTaskWithURL(url!, completionHandler: { (data, response, error) -> Void in
    do{
    returnData = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments) as! [String:AnyObject]
    print(“Json for authentication: (returnData)”);
    }
    catch {
    print(“json error: (error)”)
    }
    })
    task.resume()

    return returnData;

    The class has a return type of AnyObject, but, as my return is after the task.resume, I never get the returnData in the caller class.

    If I use NSNotificationCenter it will be the best option for this kind of application?

    Thanks for any help.

  • Vincent Joy

    Thanks very much 🙂

  • KGS

    Thanks for the easy to understand explanation and a very concise code.

  • RivieraDude

    It took years to get programmer’s to stop using “goto” of different languages, and instead -> “design” and “structure” their code rather than spaghetti wad it together. Notifications, such as this, which cross hemisphere’s of code are nothing more than the infamous “goto”. Such code signifies catastrophic structural design failure at the top of a SW package. Of course, more often than not, such get’s imposed on developers by APIs they are forced to adopt (you want to program in Apple land, you use Apple APIs). None-the-less, we should shun this type of practice vs promoting it. This NSNotificationCenter stuff is not just your typical GUI message processing loop scheme, it promotes Spaghetti code, and therefore ultimately imposes significant additional costs in any size-able SW project. Avoid it like the plague. (When you have to…you have to…but only backed into a corner).

    • Peter Michaux

      What would you do to implement the observer pattern relationship between model and controllers?

  • Kai

    Clear explanation. Thanks!

  • Nilesh Pol

    I didn’t even need to read the article, just read those 3-4 methods and done!. Awesome tutorial

  • Peter Michaux

    Using globally accessible objects like NSNotificationCenter.default binds code quite tightly. For example, unit testing is much more difficult. Dependency injection seems to be more flexible without being (significantly) more complex for the programmer.

    If a model object is passed to a controller and the controller needs to observe that model object, what do you think about that model object having its own NSNotificationCenter instance that is not the globally available default instance?

    • Andrew Bancroft

      I totally agree with you that referencing NSNotificationCenter directly like this makes automated testing that much harder.

      Finding a way to possibly _wrap_ NSNotificationCenter so that you’re accessing an API/facade that you have control over and can override might be a possible strategy for enabling DI and unit testing. I haven’t thought that all the way through yet, but I think this is a topic I want to add to my list of future content to explore and write about.

  • Yaseen Majeed

    Thanks for this lovely Blog it really helped me 🙂