Modern Concurrency: Getting Started

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

Part 1: Asynchronous Code

05. Using AsyncSequence in Views

Episode complete

Play next episode

About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 04. Asynchronous Sequences Next episode: 06. Additional Error Handling

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.

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 episode three or open the starter project for this episode. Build and run. In episode three, you used Swift concurrency to fetch this list of available stock symbols. You called availableSymbols in SymbolListView. The app needs to do this only once, so you called availableSymbols only if symbols is empty. In the simulator, select a stock symbol and click Live Ticker. This screen needs to display the selected stock symbols and what appears to be a live feed of stock prices. Stop the run. Go to LittleJohnModel and locate startTicker. You need to add code to this method to fetch a continuous sequence of values from the server. In fact, you'll fetch an asynchronous sequence, which lets you iterate over its elements asynchronously as more elements become available over time. You'll learn more about asynchronous sequences in episode nine. First, go to TickerView and call startTickers. Scroll down to the TODO below padding and add this code. This is the same task do catch code block you used to call availableSymbols in SymbolListView, but here, you don't have to check for existing values. Also, startTicker doesn't return a result. TickerView handles continuous updates, not a single return value. Now, go back to LittleJohnModel to make startTicker work. Like availableSymbols, startTicker creates a server endpoint in a guard throw statement. It doesn't return anything. Scroll up to the declaration of tickerSymbols. startTicker will store what it fetches in tickerSymbols. Like availableSymbols, the next step is to call an async URLSession method. After the guard statement, add this line. Bytes from returns an asynchronous sequence instead of a data instance, and you store this in stream. LiveURLSession is a custom session defined here. It makes requests that never expire or time out so the app can keep receiving from the server indefinitely. Unlike when you fetched the stock symbols list, you can't wait for the request to complete and only then display the data. The data must keep coming in indefinitely so the app can keep updating prices. The server will send you a single long-living response, adding more and more text to it over time. Next, in startTicker, check the URL response statusCode. This is the same statusCode check as in availableSymbols. And now comes the best part. Add this for loop. Stream is a sequence of bytes from the server. Lines is an abstraction of this sequence, an async line sequence that gives you lines of text one by one. You print each line in the console to see what it looks like. Spoiler, JSON. So you'll iterate over lines and JSON decode each line. Now, add this code in the for loop. Now, you're all set. Build and run. Select a few stock symbols and tap Live Ticker. In the console, you see that each line of text is a complete JSON array. It works, but there are warnings interspersed and also purple warnings next to tickerSymbols equals empty array and tickerSymbols equals sortedSymbols. You probably know what's wrong. You might have been feeling a little uneasy all this time because setting tickerSymbols updates the UI, and you're used to dispatching UI updates to the main queue. And yes, the purple errors come from the main thread checker, which is enabled in Xcode by default. But, over in SymbolListView, you called availableSymbols. Why didn't you get this error there? This line of code is in a SwiftUI view, updating a state property, and SwiftUI makes sure updates happen on the main thread. Back in LittleJohnModel, you're updating the published property tickerSymbols in an asynchronous context, which usually runs on a background thread. Fortunately, Swift concurrency has a solution for this. Wrap the tickerSymbols lines in some code. You remember MainActor from episode two. It's a type that runs code only on the main thread. In the next course, Beyond the Basics, you'll create other actors to make your objects thread safe. To help you check your updates are coming through, add a print statement. Build and run again. Select a stock symbol and tap Live Ticker. Everything's working now. There's just one last detail to handle. Don't stop the simulator, just keep the app running. First, a word about structured concurrency. Click back to TickerView. This task modifier in TickerView calls startTicker asynchronously. Jump to the definition of startTicker. This is the top of a task hierarchy because startTicker asynchronously awaits URLSession.bytes, which returns an async line sequence that you iterate over. At each suspension point, that is, every time you see the await keyword, the thread could change. Go back to TickerView. Since you start the entire process inside this task modifier, this async task is the parent of all those other tasks, regardless of their execution thread or suspension state. The task view modifier takes care of canceling your asynchronous code when its view goes away. Thanks to structured concurrency, all asynchronous tasks are also canceled when the user navigates out of this screen. Make sure your Xcode console is open and keep an eye on it while you tap the Back button in the simulator. TickerView disappears, and the task view modifier's task is canceled. This cancels all child tasks, including the call to startTicker. As a result, the debug logs in the console stop as well, verifying that all execution ends. However, SwiftUI doesn't like that your code is trying to present an alert after you dismiss the TickerView. Like SymbolListView, TickerView also shows an alert when its lastErrorMessage property changes. And when the runtime cancels the call to startTicker, the ongoing URLSession that's fetching the live updates throws a URL error. You don't want to set lastErrorMessage to this URL error, so you need to handle this cancellation error specially. Scroll back down to the task modifier and insert this code in the catch closure. The URLSession API throws custom errors and has a dedicated cancellation error code. Other asynchronous APIs throw a cancellation error. Here, you catch the URLSession cancellation error and don't set lastErrorMessage. Build and run. Select some stocks, tap Live Ticker, and tap Back. Now, there's no runtime warning. Congratulations, you've completed the first project in this course. The next episode challenges you to handle one more error. What if the server stops while you're in the live ticker view?