Chapter 14: HN API - Why do we need "receive(on: apiQueue)"?

private let apiQueue = DispatchQueue(label: "API", qos: .default, attributes: .concurrent)

  func story(id: Int) -> AnyPublisher<Story, Error> {
URLSession.shared
  .dataTaskPublisher(for: EndPoint.story(id).url)
  .receive(on: apiQueue)
  .map(\.data)
  .decode(type: Story.self, decoder: decoder)
  .catch { _ in Empty<Story, Error>() }
  .eraseToAnyPublisher()

}

The above is an example endpoint from the chapter. Why do we need .receive(on: apiQueue) given that dataTaskPublisher runs on an alternative queue (i.e. not the main thread) anyway?

This might be more of a personal preference - as you say effectively the work will be done on a background thread so for one or few requests using a dedicated queue will not make much difference. However I prefer my own queue because I can give it a label, precise quality of service and make sure it’s concurrent - this is handy especially when debugging but as you noticed, not necessarily required for this example :+1:t3:

1 Like

Thanks for the response!

Does dataTaskPublisher use a concurrent queue? :thinking:

Correct me if I’m wrong, but only the work from .map forward will be performed on your apiQueue with the dataTaskPublisher work being performed on its default queue?

You’re not wrong - the apiQueue in the example is for decoding the JSON concurrently. This way dataTaskPublisher does the network call on whatever thread URLSession decides to do it, then the subscription switches over to apiQueue to do the decoding.

As said, for these simple examples the performance gain is minuscule - all the queue switching is more to allow the reader to flex the operators in a more realistic context

awesome, thank you so much for the clarification!

1 Like