Modern Concurrency: Getting Started

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

Part 2: Asynchronous Sequences

14. Canceling Tasks

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 13. Downloading Chunks Next episode: 15. Using Combine

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: 14. Canceling Tasks

Xcode 14 beta detects a race condition for stopDownloads when you tap Cancel Now while using the Cloud 9 plan. Move stopDownloads and reset() to @MainActor and await the variable in the private downloadWithProgress method:

while await !stopDownloads, !accumulator.checkCompleted() {
...
if await stopDownloads, !Self.supportsPartialDownloads {
...
@MainActor var stopDownloads = false
...
@MainActor func reset() {

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

Make sure the core server is running, and continue with your project from the previous episode or open the starter project for this episode. Why is it important to cancel tasks in a timely manner? Try this, build and run the project. Select a tiff file. It's larger so it takes longer to download, giving you time to cancel it. Now tap gold. Before it finishes, tap back. Look in the console, the download keeps going but users expect this action to cancel the download. In Little John, when you tapped the back button from the ticker view, it canceled the task view modifier, which canceled its child tasks. Look in the file details view. The download button actions, aren't in a task view modifier. So there's no parent task to cancel them. You must cancel them manually. First, go to download view and add a state property. You're just creating a place to store a task to give it a name you can cancel. Task is a type like any other so you can store it in your view model or any other scope. Download task is an asynchronous task that returns no result and could throw an error. The task type doesn't return anything if it's successful so success is void. And it returns an error if there's a failure. The task you want is in download with updates action. Store it in your new state property. The time to cancel this task, is when the user navigates back to the main screen which triggers the on disappear view modifier. So add a line to this closure. Canceling download task, cancels all its child tasks and their child tasks and so on. Build and run. Select a tiff file, tap gold, tap back before it finishes. In the console, the download stops. You've implemented a simple way to manually cancel a task. Name the task, decide where to cancel it and call its cancel method. What if you want to cancel a download task without leaving download view? Look at super storage model. Look in the jump bar. There's already a bullion property stop downloads. You're Keeping track of this flag in download with progress. You'll set this property in download view. to make life interesting, you'll implement a fun use case. You'll display a partial image when the user cancels the download of a JPEG image file. The JPEG format allows for partially decoding images but other formats including tiff, don't. To support partial preview, only for canceled JPEG files. You need each task to have a local property you can set to indicate whether it supports partial downloads. Say hello to the task local property wrapper. Here's how you add a task local property to super storage model. At the top of super storage model, add a Task Local property. Task local properties must be either static for the type or global variables. Now back to download view. To set this property, in download with updates action, Replace the due closure code. First, wrap the file data line in a try await closure and then add these modifiers. The task local property wrapper has the method with value to set the property's value. You use this to set the value to true when the user starts a JPEG download. You can bind multiple values this way and you can also override the values from inner bindings, but this can become hard to read. Task storage is more useful for binding complete configuration objects or whole data models rather than separate single values or flags. As in this example. Now scroll down to the toolbar view modifier. The cancel now button needs an action. Instead of canceling the download task directly, like you did in on disappear You turn on the stop downloads flag on super storage bottle. You'll observe this flag while downloading. If it changes to true, you need to cancel download tasks that don't support partial downloads. In super storage model, in the private download with progress. Insert this code just before the return line. After each downloaded batch of bites, you check stop downloads and then supports partial downloads. If the downloading file isn't JPEG, you throw a cancellation error to exit and stop the download. If the downloading file is JPEG, you stop downloading but continue execution to return the partially downloaded file. Build and run, to try this out. first tap a tiff file, tap gold, then tap cancel now. Next, use a JPEG, wait until about a third of the JPEG file has downloaded before you cancel it or there won't be much to see. Tap gold, and there's your partial preview. Congratulations. You've used task cancellation and a task local property to add a useful feature to your app. The next fun feature you'll add is a timer to show how long a download is taking.