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.
