Modern Concurrency: Beyond the Basics

Oct 20 2022 · Swift 5.5, iOS 15, Xcode 13.4

Part 1: AsyncStream & Continuations

04. Using AsyncStream for Notifications

Episode complete

Play next episode

About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 03. Using AsyncStream to Count Down Next episode: 05. Using a Buffered AsyncStream

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Notes: 04. Using AsyncStream for Notifications

This video uses Xcode 14’s Task.sleep(until:clock:). If you use Xcode 13, replace this with Task.sleep(nanoseconds: 1_000_000_000).

Heads up... You've reached locked video content where the transcript will be shown as obfuscated text.

Refresh your browser to make sure the course server is running or restart the server in Terminal. Continue with your project from the previous episode or open the starter project for this episode. Build and run the app on two simulators. And log in with two different names. Tap the Home button on one simulator to leave the app. The app doesn't announce when you leave or when you return to the chat room. Chat users expect to see system messages when another user leaves the chat or returns. Your app can get this information from Notification Center, one of Apple's built-in frameworks. Apple recently added an asynchronous API for observing notifications. But to see how a push-based AsyncStream can wrap a synchronous API, you'll create an asynchronous sequence of notifications from the traditional notifications API. In the Utility group, open NotificationCenter+.swift and add a method to the extension. This method takes the notification name and returns an asynchronous stream of notifications. A notification stream is infinite because there isn't a fixed number of notifications. The trailing closure receives a continuation structure to control the sequence. Continuation is of type AsyncStream.continuation and offers methods to produce values and buffer them, throw errors or finish the sequence. In the AsyncStream closure, add an observer. Here you observe the default center for notifications with the given name, and when one arrives you send it out with continuation.yield. Now open BlabberModel and add a method to observe the app status and post updates to the server. Add it between chat and readMessages. Inside this method loop over willResignActiveNotifications. When a user switches to a different app or goes back to the device's home screen, your app isn't active anymore and the system posts willResignActiveNotification. You aren't actually interested in the notification's details so the loop variable is just this underscore. The UI application class is a main actor, so you need to use await to access a notification name property from this task. Now add code in the loop to post a system message when a user leaves the chat. You call say as before, except you set isSystemMessage to true. This is an automated message so you ignore any errors thrown from here. Scroll down to read messages and call observeAppStatus just before you start the updates from the chat server. So that's before the for try await loop. This creates a new asynchronous task and starts observing for notifications. You store this task in the local notifications value because, you probably guessed already, you want to cancel the observation once the loop completes. So now cancel it. This safely cancels your observation. The code in defer runs when the for try await loop throws an error or when it completes successfully. Build and run in one of your simulators. Log in, then click the home button in the simulator toolbar to close the app. Audrey went away appears on the other connected simulator. In the simulator with the closed app, tap its icon to reopen it. The app should also notify the other simulator that Audrey came back. So this is what you'll do next. In BlabberModel jump To observeAppStatus. You need a second loop in observeAppStatus to await the becomeActive notification, but the two loops must run concurrently. You don't want either loop to have to wait for the other one. So first, wrap your resignActive loop in a task. And duplicate this task to create a becomeActive task. Build and run in one of your simulators. Log in, then click the home button in the simulator bar to close the app. And you see Audrey went away on the connected simulator. In the simulator where you closed the app tap this icon to reopen it. And you see Audrey came back appears on the other simulator. And that's the other way to use AsyncStream to create a custom asynchronous sequence. Complete the challenge in the next episode to get more practice with this push based buffered AsyncStream.