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