iOS8: Where To Remove Observer for NSNotification in Swift

UPDATE: Check out the great discussion on Twitter here with @cocoaphony and @Hay about where you really should be adding and removing notification observers!

So viewDidUnload has been deprecated as of iOS 6.0, and now dealloc() can no longer be used in Swift-based ViewControllers:

dealloc Swift iOS8

This posed a challenge to me this morning as I was working with NSNotifications in my app. I’ll use my demo SeinfeldQuotes App as an example of working with NSNotifications in Swift and iOS 8.

SeinfeldQuotesApp  Create Quote App

When the user successfully creates a Quote on the Create Quote screen, I want a notification, with the new quote included, to be sent to the Seinfeld Quotes screen, which will add the new quote to the top of the table view.

Posting Notification

Posting the notification from the my CreateQuoteTableViewController once the quote is created is the same as it was in Objective-C and previous versions of iOS:

import UIKit

// making the create quote notification constant global
let NewQuoteCreatedNotification = "NewQuoteCreatedNotification"

class CreateQuoteTableViewController: UITableViewController {

    //... truncated

    // MARK: Actions
    
    @IBAction func onSaveTap(sender: UIBarButtonItem) {
        if let quote = quoteViewModel.createQuote() {

            // posting the notification
            let newQuoteCreatedNotification = NSNotification(name: NewQuoteCreatedNotification,
                object: quote)
            NSNotificationCenter.defaultCenter().postNotification(newQuoteCreatedNotification)
            navigationController?.popViewControllerAnimated(true)

        } else {
            //... truncated
        }
    }
    
    //... truncated
}

Just create your NSNotification object with the:

  • notification name – which I recommend making a constant that is easily accessible to the receiving view controller
  • an object – in my case, I’m passing in the newly created quote as the object, but this can also be nil.

Observe For Notification

Again, just like in Objective-C and previous versions of iOS, you have to register your view controller to listen to notifications. Since notifications are not view-dependent, I like to do this part in the init method:

import UIKit

class QuotesTableViewController: UITableViewController {

    //... truncated
    
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: "onQuoteCreatedNotification:",
            name: NewQuoteCreatedNotification,
            object: nil)
    }
    
    //... truncated
    
    func onQuoteCreatedNotification(notification: NSNotification) {
        if let newQuote = notification.object as? Quote {
            quotes.insert(newQuote, atIndex: 0)
            tableView.insertRowsAtIndexPaths([NSIndexPath(forRow: 0, inSection: 0)], withRowAnimation: .Automatic)
        }
    }
}

Note that the function to be executed when the notification is observed (onQuoteCreatedNotification: in the above case) cannot be private!

Remove Observer

This is the slightly tricky part. Of course you should remove the observer for your notification as soon as it’s no longer needed, but what if you do need it for the entire life-cycle of your view controller. How do you de-register from the notification with viewDidUnload and dealloc() being unavailable?

In Swift, you can put this logic in the new and special deinit method!

import UIKit

class QuotesTableViewController: UITableViewController {
    
    \\... truncated 

    deinit {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

    \\... truncated
}

According to the Swift Programming Language book:

A deinitializer is called immediately before a class instance is deallocated. You write deinitializers with the deinit keyword, similar to how intializers are written with the init keyword. Deinitializers are only available on class types.

You can read more about deinitialization in Swift in the Swift Programming Language Book here.

Enjoy the article? Join over 14,500+ Swift developers and enthusiasts who get my weekly updates.

  • You can mark onQuoteCreatedNotification: as private by adding “@objc” before “private onQuoteCreatedNotification:”. I sent pull request to the repo 🙂

  • Andrew Bancroft

    Wanted to say “thanks” for the link to the Twitter conversation. I learned a couple or three things in -addition- to when to when to remove an observer.

  • trinityluv

    Can you explain in the above example, how will you initialize QuotesTableViewController?

  • Omid

    Thanks 🙂

  • Mark Gänsicke