Errata for Combine: Asynchronous Programming with Swift 1st Edition (v1.0.3)

Creating this fresh topic to catch any typos and bugs in the 1st Edition of Combine: Asynchronous Programming with Swift (v1.0.3)

The old topic can be read here: Combine: Asynchronous Programming with Swift - Forums

1 Like

I read Chapter 3 and found it strange that after the replaceNil operator I had to do map with force unwrapping.

It turned out that this is because replaceNil has two implementations for Publishers.Sequence.

_ = Just<Int?>(1)
    .replaceNil(with: 2) // Publishers.Map<Just<Int?>, T>
    .sink(receiveValue: { (value: Int) in

_ = [1, nil, 3]
    .replaceNil(with: 2) // Publishers.Sequence<[Publishers.Sequence<Elements, Failure>.Output], Failure>
    .sink(receiveValue: { (value: Int?) in

_ = [1, nil, 3]
    .replaceNil(with: 2) // Publishers.Map<Publishers.Sequence<[Int?], Never>, T>
    .sink(receiveValue: { (value: Int) in

Hi, @sever7! I’m reaching out to the team to get a response for you. Thanks for being a reader. Hold tight!

Manda Frederick
Managing Editor, Razeware

Hey @sever7 :slight_smile:
I’m a bit confused about the question. I think the confusing thing in that chapter is the diagram.
When you do Publisher<Int?>.replaceNil(with: 1) you’ll get a Publisher<Int>, and not Publisher<Int?>.

Basically it means that in this diagram, you’ll want to see 1, 2, 3 in the output row:

Definitely something we’ll address. Does that answer your question?

When using a Sequence publisher (e.g. [1, nil, 3].publiser.replaceNil(with: 2)), it does seem like you get back an Optional, but this seems like a wrong behavior (or possibly even a bug). I’ll file a feedback/question regarding this with the Swift compiler team itself to get some clarification.

Thank you!

1 Like

Hello @freak4pc
Thank you for the detailed answer

I was confused by the fact that the book said that Publishers.Sequence<[Int?], Never> the replaceNil operator will send an Optional<Int>.

But I found that Publishers.Sequence<[Int?], Never> there are two replaceNil methods and one of them just sends the unwrapped Int.

The correct operator can be called by specifying the expected type .sink(receiveValue: {(value: Int) in }

_ = [1, nil, 3]
    .replaceNil(with: 2) // Publishers.Map<Publishers.Sequence<[Int?], Never>, T>
    .sink(receiveValue: { (value: Int) in
1 Like

This is exactly what I’m saying - that basically that makes no sense, and seems like a bug in Combine. If I do replaceNil and still get an optional value, I didn’t do much in regards to the value guarantees.

1 Like

@freak4pc thanks for the answer :smile:

Minor: V1.0.3 Chapter 15, Page 293 – RenderViewReaderView.

Full sentence: “Remember, adding the keyword to the list here will update the settings model object and in turn, will update the reader view model and refresh RenderView as well.”

On Chapter 3, page 80, for the flatMap section

Screenshot 2020-03-25 at 8.55.13 PM

Shouldn’t the correct output be like the following?

Hi, I'm Charlotte!
Hi, I'm James!
1 Like

Chapter 8: “Updating the UI after the publisher completes”

In this section, code is added to update the header when the newPhotos stream completes, but there are no instructions to add trigger this event and the Starter project does not contain it either.

The fix is to add

    selectedPhotosSubject.send(completion: .finished)

On the viewWillDisappear method of the PhotosViewController,

Chapter 4, near the end, the diagram for prefix(untilOutputFrom:).
The green “isReady” dot should be between 2 and 3, in my opinion.

Screen Shot 2020-04-22 at 16.41.38

1 Like

Chapter 4. Diagram for last(where:).
The output will only happen when the publisher completes, so it can’t happen at the same time as drawn. See below how it should be fixed, IMO.

Screen Shot 2020-04-22 at 16.43.11

1 Like

Great pieces of feedback, thanks Jacob ! @apparentsoft

1 Like

Hi folks, here’s what I got:

  • There was, what I think is, an error on Chapter 8, under “Updating the UI after the publisher completes”, there is a step that is missing, sending the completion event, I noticed what was going on by looking a the final project, but I wouldn’t have been able to do this on my own.
  • Chapter 18
    • In the DispatchTimer publisher page (on the Playground), the ‘Foundation’ import is missing.
  • Chapter 20:
    • I had a hard time swiping right on the simulator, I honestly don’t know if it was the lack of dexterity on my end or something else.
    • I decided to try my luck running the app my phone, I changed the Bundle Identifier, the Team and the Provisioning Profile, the app was installed but it crashed, both the final and starter projects crashed, so I could never try the full experience of the app, just left swipes :{
    • Super minor, there is a typo on “Review the data model”, it refers to the CoreData model as Models/ChuckNorrisJokes.xcdatamodeld instead of Models/ChuckNorrisJokes.xcdatamodel (extra d)
  • All throughout the book there were some errors related to the number markers in the code and the numbers in the description, here are some that I caught:
    • Chapter 18
      • In the extension for DispatchTimer, the markers are 5 and 6, but the text refers to them as 1 and 2
      • In the receive(subscriber: S) method, the markers are 7, 8 and 9, but the text refers to them as 1, 2 and 3
      • Something similar happens under “Adding required properties to your subscription”
      • Once again under “Creating your subscription” and “Subscribing to the publisher and handling its inputs”
    • Chapter 20
      • A different, but similar (?) error happens right after the code block under “Extending JokeManagedObject to save jokes”, the text that describes what the code is doing starts with 1, 2, then goes back to 1


In the Book Source Code and Forums section, the link to download the source code is broken when you click on it. If you copy the whole URL and paste it in the browser, it will 404 because there are encoded spaces (%20).

1 Like

@mandafrederick could you have a look at the download links?

In Chapter 2: Publishers and Subscribers:

  1. under the header Subscribing with sink(_:_:) we add the code to post and the notification and cancel the subscription. Later under Hello Cancellable it says:

Finish the Subscriber example from earlier by adding the following code:

And then has you add the same two lines as before.

  1. There is a typo after the example of "Dynamically adjusting Demand" code:

Most of this code is similar to example you’ve previously worked on in this chapter

Bug: V1.0.3 Chapter 15, Page 285 timer feature fails to work in both my copy and the ‘finished’ project

I’m guessing somethings changed on the iOS side. This book has been batting 1,000 so far and it’s hard for me to believe this didn’t used to work.

My system info:
OS: 10.15.5 (19F96)
Xcode: Version 11.5 (11E608c)
iOS: 13.5
iOS Simulator: Version 11.5 (921.9.1) SimulatorKit 581.9.1 CoreSimulator 704.12.2

It fails in the simulator as well as on my phone for both my version and the ‘finished’ project version in Chapter 15.

Adding the ‘print()’ for tracing like so…

  @State var currentDate = Date()
  private let timer = Timer.publish(every: 10, on: .main, in: .common)

Shows the following output in Xcode:

timer: receive subscription: (Timer)
timer: request unlimited
timer: request unlimited
timer: receive cancel
timer: receive subscription: (Timer)
timer: request unlimited
timer: request unlimited
My ‘educated’ guess is you had your JSON ‘polling’ the Hacker News server at one point and this worked. As soon as we get the JSON we close things down causing our timer to get a cancel message and it turns out the lights on us before we even walk into the room. :slight_smile:

Just a guess.

It would be great to get feedback or details on how to fix this going forward. Thanks for a great book!



Hi @cupofjoe - some of the underlying code in SwiftUI seems to have changed indeed recently. I had someone report a similar issue related to the timer in this chapter, have a look maybe it’s the same root cause? Errata for Combine: Asynchronous Programming with Swift 1st Edition - #67 by denisblondeau