Home > Net >  Combine - mapping errors to different types
Combine - mapping errors to different types

Time:01-06

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.

CodePudding user response:

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()

CodePudding user response:

The way to convert a stream that can error to a publisher that can Never fail is with replaceError. See my https://www.apeth.com/UnderstandingCombine/operators/operatorsErrorHandlers/operatorsreplaceerror.html

service.fetchPeople()
    .map { ViewState.loaded($0) }
    .replaceError { with: ViewState.error("Darn") }
    .eraseToAnyPublisher()

This outputs an AnyPublisher<ViewState, Never> which is just what you're after.

  •  Tags:  
  • Related