Errata for Modern Concurrency in Swift 1st Edition

Creating this topic to catch any typos and bugs in the 1st Edition of Modern Concurrency in Swift.

several of the URLs in the about chapter (section 0 chapter 4) are 404ing/500ing for me

hi David! in the markdown, some of the urls are missing https:// — I noticed this broke the link when I previewed another book, but it didn’t seem to affect published books. I’ve notified the webmaster.

Thanks for posting!

pinging @icanzilb, @freak4pc

in section 6.7, sleep is static:

static var sleep: (UInt64) async throws -> Void = Task.sleep(nanoseconds:)

But there are later code lines that must be modified for a static sleep:

let sleep = Self.sleep
BlabberModel.sleep = ...

OTOH in the final project, sleep is not static, and the other code lines work without modification.

While I’m here, in section 6.3, the first test run fails because there’s no lastRequest yet. Running the test a second time succeeds.

Hi @retebitall

Thanks for pointing this out—much appreciated. These URLs should now be fixed.


Hi ! I think there is a typo in the chapter 3: “AsyncSequences & Intermediate Task” in the chapter 3.3: “Cancelling tasks”. It is mentioned that we will learn how to cancel a task with isCancelled:

In the next section, you’ll implement your own custom cancellation logic using isCancelled.

Although the property is never used. It’s the function downloadTask?.cancel() that is called. The property isCancelled is never checked in the DownloadView neither in the SuperStorageModel.
I think that isCancelled is used implicitly by the language when we call the cancel() method maybe. But this seems surprising to be told that we will use isCancelled to then ignore it to rather call cancel().

1 Like

Nice catch! We must’ve changed the code during editing and didn’t update the instructions - I’ll have a look after the weekend. Thank you!

1 Like

@audrey I specifically followed the steps from the start of the chapter but I can’t figure out what is your comment about 6.3 about. Can you be more specific exactly at which point you see a divergence from what’s described in the chapter?

hi Marin, it’s working now, but when I first tried it, running testModelSay failed at let request = try XCTUnwrap(TestURLProtocol.lastRequest), saying it couldn’t unwrap nil. I assumed it was because lastRequest doesn’t have a value on the first run, so I ran the test again and got success.

Chapter 6 typos:

TestURLProtocol addition is:

static private var continuation: AsyncStream<URLRequest>.Continuation?

static var requests: AsyncStream<URLRequest> = {
  return AsyncStream { continuation in
    TestURLProtocol.continuation = continuation

Should be:

static private var continuation: AsyncStream<URLRequest>.Continuation?

static var requests: AsyncStream<URLRequest> = {
  return AsyncStream { continuation in
    TestURLProtocol.continuation = continuation

BlabberModel addition in Speeding up asynchronous tests section is:

static var sleep: (UInt64) async throws -> Void = Task.sleep(nanoseconds:)

Should be:

var sleep: (UInt64) async throws -> Void = Task.sleep(nanoseconds:)

In section 1.8, there are references to liveTicker(_:). Should these be startTicker(_:)?

To verify how this works in practice, navigate to the updates screen and look at the Xcode console to check that you see the debug prints from LittleJohnModel.liveTicker(_:)

Now, tap Back. TickerView disappears and the task(:slight_smile: view modifier’s task is canceled. This cancels all child tasks, including the call to LittleModel.liveTicker(:).

Also LittleModel should be LittleJohnModel.

The later code block has been fixed some time ago, if you’re reading a PDF or an ePub try re-downloading to get all the errata fixes so far.

For the former - could you please elaborate?

Thanks Audrey, fix is on its way

1 Like

There might be the case that a continuation was still stored thus not consumed, hence the finish() call on the optionally stored old one before storing the new one.

in section 3.7, the first 2 sentences of this paragraph led me to think I’d be adding didSet to isDownloadActive, but the 3rd sentence (and the rest of the section) adds didSet code to downloadTask:

Next, find the property @State var isDownloadActive = false . The first thing you’d like to do when this flag is set to true or false is to cancel any previously running timer task. Add the following didSet accessor to downloadTask

Also, if you let the file finish downloading, the timer doesn’t stop. I tried canceling it after setting isDownloadActive = false. Is there a better place to do this?

In section 3.2, the byte numbers in image 008-partial-responses are a bit wonky. For example 20,0001...60,000.

Did you intend to have size = 20000 for each partial request?

We had a number of these incorrectly retyped content on images. I’ll create a ticket for the art team to fix it.

In section 5.4, the code snippet for the last two switch cases shouldn’t include the closing brace of the switch:

case (nil, nil):
  continuation.resume(throwing: "Address encoding failed")
case let (address?, error?):
  continuation.resume(returning: address)
}   // remove this line

In section 6.4, when you explain the code for requests, you say:

You call finish() on the first line, just in case there’s an old continuation from a previous test. Then, you create a new AsyncStream and store its continuation.

But there’s no call to finish() in the code block.