This is Understanding Combine, written by Matt Neuburg. Corrections and suggestions are greatly appreciated (you can comment here). So are donations; please consider keeping me going by funding this work at http://www.paypal.me/mattneub. Or buy my books: the current (and final) editions are iOS 15 Programming Fundamentals with Swift and Programming iOS 14. Thank you!


MapError

.mapError (Publishers.MapError) takes a map function whose input is an Error. Normally, this operator does nothing; it just passes along whatever value it receives from upstream. If it receives a .finished completion, it passes that along too. But if it receives a .failure completion, it pulls out the Error contained in the failure and passes it into the map function. The map function must return an Error; this operator wraps that up in a new .failure completion and passes it on down the pipeline.

In addition to (possibly) changing the details of the error being passed downstream, this operator can change the type of the error itself. For example, having received a URLError.cancelled, this operator could replace it with a URLError.cannotConnectToHost; or it might go further and replace it with a MyError (whatever that may be). Thus this operator can change the Failure type associated with the downstream part of the pipeline.

An example I gave earlier is in conjunction with .tryMap. The only thing .tryMap knows about the type of error its map function throws is that it’s an Error. If you want the downstream part of the pipeline to characterize the Failure type more precisely, you can use .mapError with a forced downcast:

.tryMap {
    // ...
}
.mapError{$0 as! URLError}

The forced downcast is reasonable if you throw only one type of error from .tryMap and you know what it is. On the other hand, there’s no harm in leaving the downstream failure type as Error; if you throw a MyError, the error received downstream will still be a MyError even if it is typed as an Error.

NOTE: You cannot use .mapError if the upstream failure type is Never! Use .setFailureType instead.


Table of Contents