Swift 6.2: NotificationCenter Messages
In Swift 6.2, the Foundation library includes a modern
NotificationCenterAPI that uses concrete notification types instead of relying on strings and untyped dictionaries for notification names and payloads. This means you can define a notification struct with stored properties, and observers can use the type without error-prone indexing and dynamic casting.
In Swift, the
Notificationtype isnonisolated, even in cases where it’s posted on a known isolation. To provide specific isolation information and better support Swift concurrency,NotificationCenterdefines two message types. ANotificationCenter.MainActorMessagebinds to the main actor, whereas aNotificationCenter.AsyncMessageuses an arbitrary isolation. Frameworks extend these types to define distinct messages, typically corresponding to an existingNotification.Name, that declare instance properties for their values instead of using auserInfodictionary. As a result, messages can conform toSendablewhen they either don’t use properties or contain only sendable properties.If your project only needs to support Swift, you can just use the
Messagetypes. For projects with both Objective-C and Swift code, define aNotificationas well as a correspondingMessagetype.
However, the new API is part of Foundation, not Swift 6.2, so even in a pure-Swift app you can only use it on macOS 26 and later. This is a bummer because notifications aren’t a new feature that you can make available in your app only on the latest OS. Rather, they’re central to the design of the app itself. You can’t even begin migrating your code to the new API until you drop support for all the previous OS versions.
You can post a message with the
post(_:subject:)method, passing a message instance and optionally providing a subject. To receive messages, add an observer with theaddObserver(of:for:using:)method. The overloads of this method allow you to observe either messages from a single object or from any object of a given type. Observation ends when you discard the token returned fromaddObserver(of:for:using:)or after an explicit call toremoveObserver(_:).You can also receive messages as an
AsyncSequencewith themessages(of:for:bufferSize:)methods.
The optional lookup type,
NotificationCenter.MessageIdentifier, provides an SE-0299-style ergonomic experience for finding notification types when registering observers.[…]
Optional bi-directional interoperability with the existing
Notificationtype is available by using theNotification.Nameproperty and two optional methods,makeMessage(:Notification)andmakeNotification(:Self)[…][…]
Observers called via the existing, pre-Swift Concurrency
.post()methods are either called on the same thread as the poster, or called in an explicitly passedOperationQueue.However, users can still adopt
Message-style types with pre-Swift Concurrency.post()calls by providing aMessage-style type with the properNotification.Namevalue and picking the correct type betweenMainActorMessageandAsyncMessage.
See also: Fatbobman.
Previously:
- Swift 6.2
- Debugging NSNotificationCenter and NSRunLoop
- Unregistering Block-based NotificationCenter Observers
- NSNotificationCenter Thread Safety
- Safer Block-based NSNotificationCenter API
- How Not to Crash #3: NSNotification
- Phantom Types and Typed Notification Observers
- NSNotificationCenter Is Not Thread-safe
- NSNotificationCenter With Blocks Considered Harmful