From 488a77205c4a9534f7221e8c5d458b61fabd0690 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Fri, 6 Jun 2025 13:58:35 -0700 Subject: [PATCH] Add NotificationCenter.smuggle for better ergonomics --- Sources/NotificationSmuggling/Smuggled.swift | 2 +- Sources/NotificationSmuggling/Smuggling.swift | 7 +++++++ .../SmugglingTests.swift | 20 +++++++++++++++++-- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/Sources/NotificationSmuggling/Smuggled.swift b/Sources/NotificationSmuggling/Smuggled.swift index 5403fe2..cd7208d 100644 --- a/Sources/NotificationSmuggling/Smuggled.swift +++ b/Sources/NotificationSmuggling/Smuggled.swift @@ -8,7 +8,7 @@ import Foundation /// If you want to extract the contraband manually you can use the extension method ``Notification.smuggled()``. /// /// When smuggling notifications you can use ``Notification.smuggle(:object:)`` to build up a notification with the correct -/// user info automatically. +/// user info automatically, or use ``NotificationCenter.smuggle(_:)`` as a convenience method that posts the notification directly. public protocol Smuggled {} public extension Smuggled { diff --git a/Sources/NotificationSmuggling/Smuggling.swift b/Sources/NotificationSmuggling/Smuggling.swift index ea578ef..be81b1a 100644 --- a/Sources/NotificationSmuggling/Smuggling.swift +++ b/Sources/NotificationSmuggling/Smuggling.swift @@ -39,6 +39,13 @@ public extension Notification { // MARK: - public extension NotificationCenter { + /// Posts a notification that smuggles the given `Smuggled` value. + /// + /// - Parameter contraband: The `Smuggled` value to send. + func smuggle(_ contraband: Contraband) { + post(.smuggle(contraband)) + } + /// Returns an `AsyncSequence` of notifications of a specific `Smuggled` type. /// /// Each element of the sequence is a `Smuggled` value. diff --git a/Tests/NotificationSmugglingTests/SmugglingTests.swift b/Tests/NotificationSmugglingTests/SmugglingTests.swift index 2cf0428..01282d7 100644 --- a/Tests/NotificationSmugglingTests/SmugglingTests.swift +++ b/Tests/NotificationSmugglingTests/SmugglingTests.swift @@ -42,6 +42,22 @@ struct SmugglingTests { // MARK: NotificationCenter extensions + @Test(.timeLimit(.minutes(1))) + @MainActor func notificationCenterSmuggle() async { + let center = NotificationCenter() + let task = Task { + for await contraband in center.notifications(for: HitchhikersNotification.self) { + #expect(contraband.answer == 42) + return + } + } + await Task.yield() + + let contraband = HitchhikersNotification(answer: 42) + center.smuggle(contraband) + await task.value + } + // It's important that the tests and the notification-observing tasks are not on the same actor, // so we make the tests @MainActor and observe notifications on another actor. Otherwise it's // a deadlock. @@ -60,7 +76,7 @@ struct SmugglingTests { await Task.yield() let contraband = HitchhikersNotification(answer: 42) - center.post(.smuggle(contraband)) + center.smuggle(contraband) while !received { await Task.yield() } } @@ -101,7 +117,7 @@ struct SmugglingTests { await Task.yield() let contraband = HitchhikersNotification(answer: 42) - center.post(.smuggle(contraband)) + center.smuggle(contraband) while !received { await Task.yield() } }