TruMan1
TruMan1

Reputation: 36078

Create a catch/replace error counterpart that does not complete the publisher?

I'm struggling with handling errors in Combine and find it very counter-intuitive that catching or replacing an error completes and ends the publisher. For example, this ends the publisher even though I handled the exception:

Just([1, 2, 3, NaN, 5, 6])
   .tryMap { _ in throw DummyError() }
   .catch { _ in Just(4) } // or .replaceError(with: 4)
   .sink { print($0) } // <-- ends at 4 and ignores 5, 6, and anything ever again

If the publisher was subscribed to some system change, the first error will make my app dead until the user restarts the app. I would like to create a catch counterpart that does NOT end the publisher. I know flatMap is used for that, but that creates a whole other dimension of complexity such as inverting inner/outer publishers, publishers getting duplicated infinitely, back pressure, etc.

Is there a way to do something like this:

Just([1, 2, 3, NaN, 5, 6])
   .tryMap { _ in throw DummyError() }
   .ignoreError { error in
        log("Error occurred: \(error)")
   }
   .sink { print($0) } // 1, 2, 3, 5, 6

How can I encapsulate this intent in a simple custom chain command called ignoreError and make my publishers live on?

Upvotes: 1

Views: 687

Answers (1)

New Dev
New Dev

Reputation: 49590

An error completing the pipeline is part of the contract by which publishers and subscribers work. And this makes sense. If an upstream publisher throws an error and doesn't know how to recover on its own, it's basically done. It's not unlike a function throwing an error.

In your example, tryMap throws an error, and although a downstream like replaceError can transform the error for its downstream, it does not expect any more values from its upstream, so it too completes.

flatMap shields the rest of the pipeline from the error-throwing publisher. In other words, the upstream of flatMap doesn't throw an error, and flatMap itself doesn't throw an error since the returned inner publisher (the pipeline with Just/tryMap/catch) handles the error.

Just([1, 2, 3, 5, 6])
   .flatMap {
      Just($0)
        .tryMap { _ in throw DummyError() }
        .catch { _ in Just(4) } 
   }
   .sink { print($0) } 

Upvotes: 3

Related Questions