Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


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 framework or by directly including the single source file.


Reference documentation is available here.


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 scheme for your Mac.
  4. Open the Demo playground and run it.


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: 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

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() {

        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
        .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.


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.


Add the following to your Cartfile:

github "alexjohnj/TypedNotification" ~> 2.0

Swift Package Manager

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

dependencies: [
    .package(url: "", .upToNextMinor(from: "2.0.0"))