Modern Concurrency: Getting Started

Oct 18 2022 Swift 5.5, iOS 15, Xcode 13.4

Part 1: Asynchronous Code

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. Getting Started

Hi, I’m Audrey. Welcome to our course Modern Concurrency: Getting Started, about the new Swift concurrency model. In this video, you’ll find out what’s in store for you as you work through this course.

Here’s some code that should look familiar.

It calls a network API and assigns the result to a property on your view model. There are lots of potential coding errors: Did you forget to check for an error? Did you really call the completion closure in every code path?

Grand Central Dispatch was originally designed for Objective-C so, when Swift came along, Apple couldn’t integrate asynchrony tightly into the new language design.

The compiler has no way of knowing how many times you’ll call completion inside fetchServerStatus(), so it can’t optimize its lifespan and memory usage.

You need to handle memory management yourself by weakly capturing viewModel, then checking in the code to see if it was released before the closure runs.

The compiler has no way to make sure you handled the error. In fact, if you forget to handle error in the closure, or don’t invoke completion at all, the method will just freeze without warning.

The Swift concurrency model provides new tools to achieve the same goals as the GCD example:

  • async indicates that a method or function is asynchronous. Using it lets you suspend execution until an asynchronous method returns a result.
  • await indicates that your code might pause execution while it waits for an async-annotated method or function to return.
  • A Task is a unit of asynchronous work. You can wait for a task to complete or cancel it before it finishes.

This Swift concurrency code has fewer lines than the GCD example, but it provides a lot more information to the compiler and the runtime:

  • This async keyword tells the compiler that fetchServerStatus() is an asynchronous function that can suspend and resume execution one or more times in the future.
  • fetchServerStatus() either returns ServerStatus data or throws an error. The compiler checks this, so you don’t have to worry about forgetting to handle an erroneous code path!
  • Task executes its code in an asynchronous context, so the compiler knows what code is safe (or unsafe) to write in this closure. It won’t let you write potentially unsafe code, like mutating shared state.
  • You call an asynchronous function with the await keyword. This gives the runtime a chance to suspend or cancel your code and lets the system constantly update the priorities in the current task queue. The runtime handles this for you, so you don’t have to worry about threads and cores.

The new Swift concurrency model is tightly integrated with the language syntax, the Swift runtime and Xcode. In addition to async/await, you also get:

  • Context-aware code compilation: The compiler keeps track of whether a given piece of code could run asynchronously. This enables new features like actors, which differentiate between synchronous and asynchronous access to their state at compile time and protect against corrupting data by making it harder to write unsafe code.
  • Structured concurrency: Each asynchronous task is now part of a hierarchy, with a parent task and a given priority of execution. This hierarchy allows the runtime to cancel all child tasks when a parent is canceled or wait for all children to complete before the parent completes. It’s all under control. Outcomes are more obvious, with high-priority tasks running before any low-priority tasks in the hierarchy.
  • And a cooperative thread pool: The new model manages a pool of threads to make sure it doesn’t exceed the number of CPU cores available. This way, the runtime doesn’t need to create and destroy threads or constantly perform expensive thread switching. Instead, your code can suspend and, later on, resume very quickly on any of the available threads in the pool.

What About Combine?

  • Combine is a higher level, more complex framework, based on the reactive streams protocol. Its operators help you combine events and data over time from various sources, enabling you to solve very complex problems.

  • Swift concurrency offers lower-level APIs for executing asynchronous code. Use it to replace GCD and Operations with tasks and async sequences and save Combine for more complex apps.

  • It’s easy to integrate Combine into Swift concurrency, looping asynchronously over Publisher.values. You’ll do this in Part 2 of this course.

  • And Swift concurrency APIs are available on Linux while Combine isn’t.

  • In this course, you’ll learn how to use fundamental concepts like Task, MainActor, async/await, async let and AsyncSequence. And you’ll practice different ways to cancel tasks.

  • The next course, Modern Concurrency: Beyond the Basics covers AsyncStream, Continuations, Unit Testing, TaskGroup, Actors and thread-safety.

You’ll implement asynchronous and concurrent code in real iOS apps. And the course materials include a server to respond to requests from these apps.

Your first app is a stock ticker app. First, you’ll fetch a list of stock symbols, then you’ll fetch and display a never-ending sequence of stock prices.

In Part 2, you’ll work on SuperStorage, a cloud file storage app with three download plans.

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 or macOS 12.
  • An 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.

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 some asynchronous code in a playground. Then you’ll use what you learn in your first asynchronous app.