Modern Concurrency: Beyond the Basics

Oct 20 2022 Swift 5.5, iOS 15, Xcode 13.4

Part 1: AsyncStream & Continuations

1. Introduction

Lesson Complete

Play Next Lesson
Save for later
About this episode
See forum comments
Cinema mode Mark as Complete Download course materials
Next episode: 2. AsyncStream

Hi, I’m Audrey. Welcome to our course Modern Concurrency: Beyond the Basics. In this video, you’ll find out what’s in store for you as you work through this course.

This course follows on from Modern Concurrency: Getting Started and assumes you’re familiar with what that course covers You should be comfortable calling and writing async functions and iterating over asynchronous sequences.

In Part 1, you’ll learn about AsyncStream, unit testing & continuations. Part 2 introduces TaskGroup for truly dynamic concurrency and goes beyond MainActor, to show you how to use the Actor API to make your code thread-safe.

Now, I’ll tell you a little more about the topics in Part 1.

Whenever Apple introduces something new, like Swift or SwiftUI, they don’t expect developers to stop using the old way and switch completely over to the new. There are always bridging tools to make it easier to integrate existing code with the new stuff.

AsyncStream is one of these tools: You can use it to create async sequences from the completion handlers and delegate methods of existing asynchronous APIs.

You’ll also learn how to use AsyncStream to create custom asynchronous sequences without adding new types to your app. You just specify the element type, then supply a trailing closure to provide the sequence.

There are two types of closure. You’ll use one type to create a countdown sequence and the other type to stream notifications.

Since Apple first introduced Grand Central Dispatch, it has advised developers on how to avoid the dangers of thread explosion.

In the Swift concurrency system, there are at most only as many threads as there are CPU cores. When threads execute work under Swift concurrency, the system uses a lightweight object known as a continuation to track where to resume work on a suspended task.

When a task suspends, it captures its state in a continuation. Its thread can resume execution of another task, recreating its state from the continuation it created when it suspended. The cost of this is a function call. Switching between task continuations is much cheaper and more efficient than performing context switches.

This all happens behind the scenes when you use async functions. But you can also get your hands on a continuation to manually resume execution. The buffering form of AsyncStream uses a continuation to yield stream elements. And you’ll use a manual continuation API to help you convert existing code like completion handlers and delegate methods into async functions.

Before Swift concurrency, XCTest didn’t have language support for running asynchronous code. You had to rely on workarounds like XCTWaiter and expectations. With Swift concurrency, you just declare any test method as async. When you await an asynchronous function, the test suspends. When it resumes, you can verify the output as usual.

You’ll work through a simple test case with a single await and a more complex one that captures test output over time.

You’ll also create some tools to create tasks that time out instead of hanging and also speed up task duration.

The app you’ll work on in Part 1 is a messaging app called Blabber. The starter project already implements the basic chat view:

  • You’ll implement a countdown timer using both AsyncStream closure types.
  • Then you’ll use the buffered AsyncStream to add notifications when a user leaves or returns.
  • You’ll use continuations with CoreLocation to let users show their location.
  • And you’ll learn how easy it is to write unit tests for Blabber’s networking code.

Here’s what you need to work through these courses:

  • A Mac running macOS Monterey (12.0) or later. Big Sur should work, but this course uses macOS Monterey, so your mileage may vary.
  • Xcode 13: Since Xcode 13.2, all the new Swift concurrency features work with iOS 13 / macOS 10.15 SDK (or later). If you use an older version of Xcode 13, you’ll only get Swift concurrency support when targeting iOS 15 / macOS 12.
  • Intermediate level of Swift: You’ll appreciate Swift concurrency more if you’re familiar with Grand Central Dispatch and URLSession. And you’ll be doing a lot of throwing and do-try-catching errors.
  • SwiftUI: The sample projects have all the views and navigation code in place, but you should have some familiarity with SwiftUI. You’ll need to add a few view modifiers and actions to call your asynchronous methods from SwiftUI views.
  • Basics of async/await and AsyncSequence, equivalent to the Getting Started course.

This course is based on the book by the amazing Marin Todorov. He’s icanzilb on Twitter.

This video series has been tech edited by Adrian Strahan. Find him on twitter as adrianstrahan.

In the next episode, you’ll explore AsyncStream in a playground. Then you’ll use what you learned in the Blabber app.