Search code examples
swiftcombine

Combine - mapping errors to different types


I've created this publisher chain:

enum ViewState {
  case loading, loaded([Person]), error(String)
}

var viewStatePublisher: AnyPublisher<ViewState, Never> {
  service.fetchPeople()
    .map { ViewState.loaded($0) }
    .eraseToAnyPublisher()
}

fetchPeople can fail, and I'd like to propagate that down the publisher chain as a ViewState.error(String) value. Here's a rough idea of what I'm trying to do:

service.fetchPeople()
  .mapError { error -> AnyPublisher<ViewState, Never> in
    ViewState.error(error.localizedDescription)
  }
  .map { ViewState.loaded($0) }
  .eraseToAnyPublisher()

However, mapError doesn't work that way. I'm having trouble finding other alternatives to doing this.


Solution

  • You need catch to replace errors thrown by the upstream publisher with a new downstream Publisher.

    Inside the catch, you can wrap the error in a Just, which is a Publisher that emits a single value immediately.

    service.fetchPeople()
        .map { ViewState.loaded($0) }
        .catch { Just(ViewState.error($0.localizedDescription)) }
        .eraseToAnyPublisher()