Chapters

Hide chapters

Modern Concurrency in Swift

Second Edition · iOS 16 · Swift 5.8 · Xcode 14

Section I: Modern Concurrency in Swift

Section 1: 11 chapters
Show chapters Hide chapters

4. Custom Asynchronous Sequences With AsyncStream
Written by Marin Todorov

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

In previous chapters, you’ve learned a few different ways to integrate asynchronous code in your apps. By now, you’re hopefully comfortable calling and writing async functions and iterating over asynchronous sequences.

In this chapter, you’ll dive deeper into how to create your very own custom async sequences using AsyncStream. Using this method grants you complete control over the asynchronous sequence and makes it trivial to wrap your own existing asynchronous APIs as async sequences.

In this chapter, you’ll work through the Blabber app to explore these topics.

Getting Started With the Blabber App

Blabber is a messaging app that lets you chat with friends. It has some neat features like location sharing, a countdown timer and a friendly — but somewhat unpredictable — chatbot.

Like all projects in this book, Blabber’s SwiftUI views, navigation and data model are already wired up and ready for you. Blabber has a similar foundation to the projects you’ve already worked on, like LittleJohn and SuperStorage. It’s a connected app powered by a server API. Some of that code is already included in the starter because it works the same as in earlier projects.

Open the starter version of Blabber in this chapter’s materials, under projects/starter. When you complete the app, it will feature a working login screen, where you can choose your user name, and a chat screen to socialize with friends:

At the moment, you can enter a user name, but nothing else works. Your goal is to make asynchronous calls to the server, then provide live updates in the app by reading from a long-living server request.

Before starting to work on the app, start the book server. If you haven’t already done that, navigate to the server folder 00-book-server in the book materials-repository and enter swift run. The detailed steps are covered in Chapter 1, “Why Modern Swift Concurrency?”.

Adding Functionality to Blabber

In the first section of this chapter, you’ll work on finishing some missing app functionality. That will give you a solid start when you work on your own custom sequences in the following sections.

Parsing the Server Responses

The custom chat protocol that the book server implements sends a status as the first line, then continues with chat messages on the following lines. Each line is a JSON object, and new lines appear whenever users add chat messages. This is all part of the same long-living request/response. Here’s an example:

Storing and using the chat information

To store this information, add the following code immediately after the decoding:

Digging into AsyncSequence, AsyncIteratorProtocol and AsyncStream

In the previous section, you learned that an asynchronous sequence lets you access its elements via its iterator. In fact, defining the element type of the sequence and providing an iterator are the only requirements of the AsyncSequence protocol:

Meqaj WudoyvovaopDifvon OIXivizi.ufeaggajeec xawmluuf dosjbnufe xibuzevufaez varoquhejias divx gawj dily xuxj

Simple Asynchronous Sequences

What would a simple implementation of an asynchronous sequence look like?

Simplifying Asynchronous Sequences with AsyncStream

To streamline creating asynchronous sequences, Apple has added a type called AsyncStream. It conforms to AsyncSequence and produces values from a single closure, where you define the custom logic for your sequence.

Creating an Asynchronous Timer With AsyncStream

The countdown feature in the Blabber app adds an element of drama to your chats by counting down before showing your latest message. The countdown sequence won’t do very much. It will start at three, count down to one before finally terminating with the user’s message:

4 ... 9 ... 8 ... 🎉 munkofi

Building Your Timer Logic

Now, you will build up the timer logic out of few simple steps. Insert this inside AsyncStream’s trailing closure:

Adding an Asynchronous Stream to NotificationCenter

Going back and forth between closure-based asynchronous APIs and the modern async/await-based APIs can be tedious. Luckily, you can easily wrap your existing APIs in an async sequence, so you can integrate all of your async work in a single, easy-to-use interface.

Feqomesolien Lepdey Wusoxuvipiid Fonaqijicoop OvvslHvdeup Jajufusotuoz Xinicesoleem

Notifying Participants When a User Leaves

To post a system message that the user has left the chat, add the following inside the loop you added at the end of the previous section:

Notifying Participants When a User Returns

To wrap up this section, you’ll also observe didBecomeActiveNotification to let the chat participants know when a user returns to the chat.

Extending AsyncSequence

Extending existing types is not an async/await feature per se, but with AsyncStream being so simple to use, your attention might stray away from the possibilities of extending the concrete AsyncStream type or even the more generic AsyncSequence protocol.

AwsnkRupiegku snifos(...) codjuv(...) caz(...) levEoqx(...)

Key Points

  • You can use iterators and loops to implement your own processing logic when consuming an AsyncSequence.
  • AsyncSequence and its partner in crime, AsyncIteratorProtocol, let you easily create your own asynchronous sequences.
  • AsyncStream is the easiest way to create asynchronous sequences from a single Swift closure.
  • There are two ways to create an AsyncStream - an unfolding variant, where the closure returns a value or nil to mark the end of the sequence, or a continuation variant, where the closure receives a continuation value that you can pass around and use in your non-async code.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2026 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now