TypedNotification

TypedNotification is a Swift library that adds some type-safety to Foundation’s NotificationCenter. The library is small and can be added to your project either as a static framework or by directly including the single source file.

Usage

Playground

This repository includes an annotated playground that demonstrates the features of TypedNotification. To use it:

  1. Clone the repository.
  2. Open TypedNotification.xcworkspace
  3. Build the TypedNotification (Playground) scheme.
  4. Open the Demo playground and run it.

Overview

For each notification in your application, create a new type that conforms to the TypedNotification protocol:

struct DataStoreDidSaveNotification: TypedNotification {

    /// The data store posting the notification.
    let object: DataStore // <- This property is required by the protocol.

    let insertedObjects: Set<Model>
}

When conforming, you must provide a type and the storage for an object attached to the notification. Additional data that would normally be included in a notification’s userInfo dictionary can be provided as properties on the notification.

To post a notification, create an instance of the notification and call post(_:) on a NotificationCenter:

NotificationCenter.default.post(DataStoreDidSaveNotification(object: dataStore, insertedObjects: insertedObjects))

To observe a notification use the addObserver(forType:object:queue:using) method on NotificationCenter. This is similar to the Foundation method but takes a type of notification to observe instead of the name and returns a NotificationObservation to manage the observation:

let observation = NotificationCenter.default.addObserver(forType: DataStoreDidSaveNotification.self, object: nil, queue: nil) { note in
    print(note.insertedObjects)
}

Note that the type of note passed to the callback block is a DataStoreDidSaveNotification.

The returned NotificationObservation instance manages the lifetime of the observation. When the instance is deallocated, the observation stops.

Notification Observation Bags

TypedNotification provides a convenient type for working with NotificationObservations. A NotificationObservationBag stores multiple observation instances and removes them all when deallocated. You can use this to tie the lifetime of an observation to another object:

class ViewController: UIViewController {

    let notificationBag = NotificationObservationBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        NotificationCenter.default.addObserver(forType: DataStoreDidSaveNotification.self, object: nil, queue: nil) { [unowned self] note in
              self.doSomething(with: note.insertedObjects)
          }
          .stored(in: notificationBag)
    }
}

Here, when a ViewController is deallocated, so to is its notification bag and the observation set up in viewDidLoad() goes away.

This is really useful behaviour so TypedNotification includes a variant of addObserver for normal Notifications that also returns a NotificationObservation:

func setUpKeyboardObservation() {
    NotificationCenter.default.addObserver(forNotificationNamed: UIWindow.keyboardWillShowNotification, object: nil, queue: nil) { note in
            print(note.userInfo?[UIWindow.keyboardFrameEndUserInfoKey])
        }
        .stored(in: notificationBag)
}

Requirements & Installation

TypedNotification requires a version of Xcode that can compile Swift 5 code. Additionally it requires a deployment target targeting iOS 10+ or macOS 10.12+ because of a dependency on os.lock.

You’ve got four options for installation.

Manual Installation

Copy TypedNotification.swift from the Sources directory.

CocoaPods

Add the following to your Podfile:

pod 'AJJTypedNotification', '~> 2.0'

Note that the name of the module (i.e., what you import) is TypedNotification but the pod is AJJTypedNotification.

Carthage

Add the following to your Cartfile:

github "alexjohnj/TypedNotification" ~> 2.0

TypedNotification builds as a static framework so you’ll find the output in Build/$PLATFORM/Static. Remember not to embed the framework in your application, just link against it.

Swift Package Manager

Add the following to your Package.swift file’s dependencies:

dependencies: [
    .package(url: "https://github.com/alexjohnj/TypedNotification.git", .upToNextMinor(from: "2.0.0"))
]

License

MIT