{"id":49833,"date":"2025-10-29T14:16:24","date_gmt":"2025-10-29T18:16:24","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=49833"},"modified":"2025-10-29T14:16:24","modified_gmt":"2025-10-29T18:16:24","slug":"swift-6-2-notificationcenter-messages","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2025\/10\/29\/swift-6-2-notificationcenter-messages\/","title":{"rendered":"Swift 6.2: NotificationCenter Messages"},"content":{"rendered":"<p><a href=\"https:\/\/www.swift.org\/blog\/swift-6.2-released\/\">Holly Borla<\/a>:<\/p>\n<blockquote cite=\"https:\/\/www.swift.org\/blog\/swift-6.2-released\/\">\n<p>In Swift 6.2, the Foundation library includes a modern <code>NotificationCenter<\/code> API 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.<\/p><\/blockquote>\n\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/foundation\/notification-center-messages\">Apple<\/a>:<\/p>\n<blockquote cite=\"https:\/\/developer.apple.com\/documentation\/foundation\/notification-center-messages\"><p>In Swift, the <a href=\"https:\/\/developer.apple.com\/documentation\/foundation\/notification\"><code>Notification<\/code><\/a> type is <code>nonisolated<\/code>, even in cases where it&rsquo;s posted on a known isolation. To provide specific isolation information and better support Swift concurrency, <code>NotificationCenter<\/code> defines two message types. A <a href=\"https:\/\/developer.apple.com\/documentation\/foundation\/notificationcenter\/mainactormessage\"><code>NotificationCenter.MainActorMessage<\/code><\/a> binds to the main actor, whereas a <a href=\"https:\/\/developer.apple.com\/documentation\/foundation\/notificationcenter\/asyncmessage\"><code>NotificationCenter.AsyncMessage<\/code><\/a> uses an arbitrary isolation. Frameworks extend these types to define distinct messages, typically corresponding to an existing <a href=\"https:\/\/developer.apple.com\/documentation\/foundation\/notification\/name-swift.typealias\"><code>Notification.Name<\/code><\/a>, that declare instance properties for their values instead of using a <code>userInfo<\/code> dictionary. As a result, messages can conform to <a href=\"https:\/\/developer.apple.com\/documentation\/Swift\/Sendable\"><code>Sendable<\/code><\/a> when they either don&rsquo;t use properties or contain only sendable properties.<\/p><p>If your project only needs to support Swift, you can just use the <code>Message<\/code> types. For projects with both Objective-C and Swift code, define a <a href=\"https:\/\/developer.apple.com\/documentation\/foundation\/notification\"><code>Notification<\/code><\/a> as well as a corresponding <code>Message<\/code> type.<\/p><\/blockquote>\n<p>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&rsquo;t a new feature that you can make available in your app only on the latest OS. Rather, they&rsquo;re central to the design of the app itself. You can&rsquo;t even begin migrating your code to the new API until you drop support for all the previous OS versions.<\/p>\n\n<blockquote cite=\"https:\/\/developer.apple.com\/documentation\/foundation\/notification-center-messages\"><p>You can post a message with the <code>post(_:subject:)<\/code> method, passing a message instance and optionally providing a subject. To receive messages, add an observer with the <code>addObserver(of:for:using:)<\/code> 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 from <code>addObserver(of:for:using:)<\/code> or after an explicit call to <a href=\"https:\/\/developer.apple.com\/documentation\/foundation\/notificationcenter\/removeobserver(_:)-2gmm0\"><code>removeObserver(_:)<\/code><\/a>.<\/p><p>You can also receive messages as an <a href=\"https:\/\/developer.apple.com\/documentation\/Swift\/AsyncSequence\"><code>AsyncSequence<\/code><\/a> with the <code>messages(of:for:bufferSize:)<\/code> methods.<\/p><\/blockquote>\n\n<p><a href=\"https:\/\/github.com\/swiftlang\/swift-foundation\/blob\/main\/Proposals\/0011-concurrency-safe-notifications.md\">SF-0011<\/a>:<\/p>\n<blockquote cite=\"https:\/\/github.com\/swiftlang\/swift-foundation\/blob\/main\/Proposals\/0011-concurrency-safe-notifications.md\"><p>The optional lookup type, <code>NotificationCenter.MessageIdentifier<\/code>, provides an <a href=\"https:\/\/github.com\/swiftlang\/swift-evolution\/blob\/main\/proposals\/0299-extend-generic-static-member-lookup.md\">SE-0299<\/a>-style ergonomic experience for finding notification types when registering observers.<\/p><p>[&#8230;]<\/p><p>Optional bi-directional interoperability with the existing <code>Notification<\/code> type is available by using the <code>Notification.Name<\/code> property and two optional methods, <code>makeMessage(:Notification)<\/code> and <code>makeNotification(:Self)<\/code>[&#8230;]<\/p><p>[&#8230;]<\/p><p>Observers called via the existing, pre-Swift Concurrency <code>.post()<\/code> methods are either called on the same thread as the poster, or called in an explicitly passed <code>OperationQueue<\/code>.<\/p><p>However, users can still adopt <code>Message<\/code>-style types with pre-Swift Concurrency <code>.post()<\/code> calls by providing a <code>Message<\/code>-style type with the proper <code>Notification.Name<\/code> value and picking the correct type between <code>MainActorMessage<\/code> and <code>AsyncMessage<\/code>.<\/p><\/blockquote>\n\n<p>See also: <a href=\"https:\/\/fatbobman.com\/en\/posts\/notificationcentermessage-a-new-concurrency-safe-notification-experience-in-swift-62\/\">Fatbobman<\/a>.<\/p>\n\n<p>Previously:<\/p>\n<ul>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2025\/10\/29\/swift-6-2\/\">Swift 6.2<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2018\/02\/23\/debugging-nsnotificationcenter-and-nsrunloop\/\">Debugging NSNotificationCenter and NSRunLoop<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2018\/01\/09\/unregistering-block-based-notificationcenter-observers\/\">Unregistering Block-based NotificationCenter Observers<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2017\/07\/24\/nsnotificationcenter-thread-safety\/\">NSNotificationCenter Thread Safety<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2015\/08\/26\/safer-block-based-nsnotificationcenter-api\/\">Safer Block-based NSNotificationCenter API<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2015\/05\/23\/how-not-to-crash-3-nsnotification\/\">How Not to Crash #3: NSNotification<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2015\/02\/01\/phantom-types-and-typed-notification-observers\/\">Phantom Types and Typed Notification Observers<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2014\/04\/22\/nsnotificationcenter-is-not-thread-safe\/\">NSNotificationCenter Is Not Thread-safe<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2013\/11\/20\/nsnotificationcenter-with-blocks-considered-harmful\/\">NSNotificationCenter With Blocks Considered Harmful<\/a><\/li>\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>Holly Borla: In Swift 6.2, the Foundation library includes a modern NotificationCenter API 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. Apple: [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"apple_news_api_created_at":"2025-10-29T18:16:27Z","apple_news_api_id":"959d4d4e-b352-4470-a395-b757582b55fb","apple_news_api_modified_at":"2025-10-29T18:16:27Z","apple_news_api_revision":"AAAAAAAAAAD\/\/\/\/\/\/\/\/\/\/w==","apple_news_api_share_url":"https:\/\/apple.news\/AlZ1NTrNSRHCjlbdXWCtV-w","apple_news_coverimage":0,"apple_news_coverimage_caption":"","apple_news_is_hidden":false,"apple_news_is_paid":false,"apple_news_is_preview":false,"apple_news_is_sponsored":false,"apple_news_maturity_rating":"","apple_news_metadata":"\"\"","apple_news_pullquote":"","apple_news_pullquote_position":"","apple_news_slug":"","apple_news_sections":"\"\"","apple_news_suppress_video_url":false,"apple_news_use_image_component":false,"footnotes":""},"categories":[4],"tags":[31,2741,30,2742,71,2200,2854,901],"class_list":["post-49833","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-ios","tag-ios-26","tag-mac","tag-macos-tahoe-26","tag-programming","tag-swift-concurrency","tag-swift-foundation","tag-swift-programming-language"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/49833","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/comments?post=49833"}],"version-history":[{"count":1,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/49833\/revisions"}],"predecessor-version":[{"id":49834,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/49833\/revisions\/49834"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=49833"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=49833"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=49833"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}