That's how I've been doing it in theory, but I moved away from doing it with the async APIs because they delay the call versus the traditional APIs, meaning for these specific APIs (entering foreground/background) they're no longer as accurate.
For instance willEnterForeground is (per docs) supposed to come, well, before foreground is entered, and it does with the old APIs, but not if you use an async sequence, which makes trusting the activationState difficult.
Since you're assigning both tasks to the same property you'd only cancel the second task on deinit and the first one would keep on running. You'll want to store your tasks in an array or two separate properties to make sure that you can cancel them both.
I'm also not entirely sure that you don't have a retain cycle here since your Task has a strong implicit self capture to call and await your foreground() and background() methods. You'll want to make sure those tasks use a [weak self] instead.
which doesn't require having a variable or an explicit cancellation in deinit (although you may still have a variable if you need to cancel notification subscription earlier).
I came across the cancellation issue as I was testing this further. It does seem like the most appropriate way to observe multiple notification sequences is to have multiple tasks.
.task {
for await _ in NotificationCenter.default.notifications(named: UIScene.didEnterBackgroundNotification) {
// do stuff
}
}
.task {
for await _ in NotificationCenter.default.notifications(named: UIScene.willEnterForegroundNotification) {
// do stuff
}
}
For this example, In SwiftUI, you have ScenePhase which means you don't need to deal with asynchronous sequences at all.
For other use cases, such as OP's, unless you'd be happy with the event arriving via the equivalent of a call to DispatchQueue.main.async { ... } (and more than likely a round-trip to some other queue, too), I wouldn't use asynchronous sequences at all. Asynchronous sequences are great tools, and definitely have their place, but in my opinion that place is not for same actor (i.e. @MainActor to @MainActor) event dispatch/observation, especially if timing/ordering or maintaining some local invariant is important.