What Is Notification.Name and How to Use It

Swift underwent drastic changes with the release of version 3 of the language. As you probably know, those changes weren't limited to the language and the standard library. Apple made many, many changes to the Foundation framework, for example.

Notification center was one of the APIs that received a facelift. The result is an API that's succinct and more intuitive. Despite these changes, there seems to be quite a bit of confusion surrounding notification names. Let me show you what the problem is and how to solve it.

What Is Notification.Name

To register a class instance as an observer for a notification, you invoke addObserver(_:selector:name:object:), a method of the NotificationCenter class. Notice that you no longer need to use the NS prefix. Many types of the Foundation framework have dropped the NS prefix.

import UIKit

class ViewController: UIViewController {

    // MARK: - Properties

    @IBOutlet var textField: UITextField!

    // MARK: - View Life Cycle

    override func viewDidLoad() {
        super.viewDidLoad()

        // Add Observer
        NotificationCenter.default.addObserver(self, selector: #selector(textDidChange(_:)), name: Notification.Name.UITextFieldTextDidChange, object: textField)
    }

    // MARK: - Notification Handling

    @objc private func textDidChange(_ notification: Notification) {

    }

}

The third parameter of the addObserver(_:selector:name:object:) method is what interests us most. The name parameter is of type Notification.Name. What is that about? Because the compiler knows what type to expect, we can omit Notification.Name.

override func viewDidLoad() {
    super.viewDidLoad()

    // Add Observer
    NotificationCenter.default.addObserver(self, selector: #selector(textDidChange(_:)), name: .UITextFieldTextDidChange, object: textField)
}

We can find out more about the Notification.Name type by pressing Command and clicking UITextFieldTextDidChange. This takes us to the public interface of the UITextField class, which is defined in the UIKit framework. It appears that UITextFieldTextDidChange is a static constant property of NSNotification.Name, which is a synonym for Notification.Name.

extension NSNotification.Name {

    public static let UITextFieldTextDidBeginEditing: NSNotification.Name

    public static let UITextFieldTextDidEndEditing: NSNotification.Name

    public static let UITextFieldTextDidChange: NSNotification.Name

}

We're almost there. To understand what Notification.Name is, we need to dive a bit deeper. Press Command and click Name of Notification.Name. This takes you to an extension for NSNotification.

extension NSNotification {

    public struct Name : RawRepresentable, Equatable, Hashable, Comparable {

        public init(_ rawValue: String)

        public init(rawValue: String)
    }

}

Name appears to be a structure, a nested type of NSNotification (Notification). It conforms to four protocols, including RawRepresentable. To create an instance of the Name structure, we need to invoke one of two initializers, init(rawValue:) or init(_:).

The documentation of Notification.Name gives us another hint to better understand what Notification.Name is and how to use it. The summary reads like this.

The type used for the name of a notification.

This makes sense. Right? And we already knew this by inspecting the addObserver(_:selector:name:object:) method. But the documentation also tells us something else.

In Objective-C, NSNotification names are type aliased to the NSString class. In Swift, Notification names use the nested NSNotification.Name type.

What Is Notification.Name in Swift

That gives us the answer we were looking for. If you switch to Objective-C in the documentation, you can see the type definition of NSNotificationName.

typedef NSString *NSNotificationName;

What Is NSNotificationName in Objective-C

How to Use Notification.Name

What I like about Notification.Name is that we no longer need to define string constants in one or multiple places in a project. The solution has become much easier, more elegant, and in line with Swift's API design.

This is an example I have used in a project of my own. The implementation is simple now that we understand what Notification.Name is and how we can create an instance of the Name structure.

import Foundation

extension Notification.Name {

    static let DidResetStatistics = Notification.Name("DidResetStatistics")

}

We import the Foundation framework to have access to the Notification.Name structure and create an extension for Notification.Name. In this extension, we define a static constant property DidResetStatistics. The value we assign to the static constant property is an instance of the Notification.Name structure. The raw value of the instance is a string, "DidResetStatistics".

When we explored the public interface of the Name structure, we noticed that Name has two initializers. We could write the above example also like this.

import Foundation

extension Notification.Name {

    static let DidResetStatistics = Notification.Name(rawValue: "DidResetStatistics")

}

If DidResetStatistics needs to be publicly available, then you need to prefix it with the public keyword. It's currently only accessible from within the module it's defined in.

Using DidResetStatistics is identical to notification names defined by the Foundation framework.

import UIKit

class ViewController: UIViewController {

    // MARK: - View Life Cycle

    override func viewDidLoad() {
        super.viewDidLoad()

        // Add Observer
        NotificationCenter.default.addObserver(self, selector: #selector(didResetStatistics(_:)), name: Notification.Name.DidResetStatistics, object: nil)
    }

    // MARK: - Notification Handling

    @objc private func didResetStatistics(_ notification: Notification) {

    }

}

That's another mystery solved. I hope this tutorial has answered any questions you have about notification names and Swift.

Stop Writing Swift That Sucks

Download the Swift Patterns I Swear By