Replies: 5 comments 8 replies
-
Hi @shannoga, the reason we "erase" the If you don't plan on controlling the notifications, then there is no reason to use |
Beta Was this translation helpful? Give feedback.
-
I will try this, |
Beta Was this translation helpful? Give feedback.
-
Here is my final version if that helps someone. I needed to add support for iOS 14 as Notifications is iOS 15 +. extension DependencyValues {
var notifications: Notifications {
get { self[Notifications.self] }
set { self[Notifications.self] = newValue }
}
}
struct Notifications: DependencyKey {
var notification: @Sendable (String, AnyObject?) async -> AsyncStream<Notification>
var applicationDidFinishLaunching: @Sendable () async -> AsyncStream<Notification>
var applicationDidBecomeActive: @Sendable () async -> AsyncStream<Notification>
var applicationWillEnterForeground: @Sendable () async -> AsyncStream<Notification>
var applicationWillResignActive: @Sendable () async -> AsyncStream<Notification>
var applicationDidEnterBackgroundNotification: @Sendable () async -> AsyncStream<Notification>
var applicationWillTerminateNotification: @Sendable () async -> AsyncStream<Notification>
var applicationDidReceiveMemoryWarning: @Sendable () async -> AsyncStream<Notification>
static var liveValue: Notifications {
@Sendable func buildNotification(named name: Notification.Name, object: AnyObject? = nil) -> AsyncStream<Notification> {
if #available(iOS 15, *) {
return AsyncStream {
NotificationCenter.default
.notifications(named: name, object: object)
.map { $0 }
}
} else {
return AsyncStream { continuation in
let cancellable = NotificationCenter.default
.publisher(for: name)
.sink() { notification in
continuation.yield(notification)
}
continuation.onTermination = { @Sendable _ in
cancellable.cancel()
}
}
}
}
return .init(
notification: { name, object in
let notificationName = Notification.Name(rawValue: name)
return buildNotification(named: notificationName, object: object)
}, applicationDidFinishLaunching: {
return await buildNotification(named: UIApplication.didFinishLaunchingNotification)
}, applicationDidBecomeActive: {
return await buildNotification(named: UIApplication.didBecomeActiveNotification)
}, applicationWillEnterForeground: {
return await buildNotification(named: UIApplication.willEnterForegroundNotification)
}, applicationWillResignActive: {
return await buildNotification(named: UIApplication.willResignActiveNotification)
}, applicationDidEnterBackgroundNotification: {
return await buildNotification(named: UIApplication.didEnterBackgroundNotification)
}, applicationWillTerminateNotification: {
return await buildNotification(named: UIApplication.willTerminateNotification)
}, applicationDidReceiveMemoryWarning: {
return await buildNotification(named: UIApplication.didReceiveMemoryWarningNotification)
})
}
}
extension AsyncStream {
public init<S: AsyncSequence>(
bufferingPolicy limit: Continuation.BufferingPolicy = .unbounded,
@_implicitSelfCapture @_inheritActorContext _ makeUnderlyingSequence: @escaping @Sendable ()
async -> S
) where S.Element == Element {
self.init(bufferingPolicy: limit) { (continuation: Continuation) in
let task = Task {
do {
for try await element in await makeUnderlyingSequence() {
continuation.yield(element)
}
} catch {}
continuation.finish()
}
continuation.onTermination =
{ _ in
task.cancel()
}
// NB: This explicit cast is needed to work around a compiler bug in Swift 5.5.2
as @Sendable (Continuation.Termination) -> Void
}
}
} @stephencelis |
Beta Was this translation helpful? Give feedback.
-
Really cool! Hmm...I'm actually wondering whether I should adopt this approach in my code. I'm currently trying to test some functionality where the reducer's state changes whenever it receives a NotificationCenter update from an AsyncStream and this looks like something I should adopt. @shannoga have you been able to write tests that utilize this functionality? I also created a separate discussion about this since my question is more related toward testing than the discussion at hand. |
Beta Was this translation helpful? Give feedback.
-
For iOS 15+ For iOS 18+ Example:
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi
I am trying to build a generic notification center dependency.
I found an example in your case studies (02-Effects-LongLiving) and wanted to implement it in a similar way using
AsyncStream
.I have two questions:
Notification
dose not conform toSendable
, is there a way to avoid this warning?NotificationCenter.Notifications
which conforms toAsyncSequence
and use it in the reducer, I wonder why Sequence is a better choice (Was that to avoid dependency on Notification?)Thanks a lot!
Beta Was this translation helpful? Give feedback.
All reactions