And what shall we use instead?
I'm surprised that nobody asked this before.
You don't strictly need tryFlatMap
, because flatMap
's transform returns a publisher. You can use do/catch
inside the transform closure and return a Fail
publisher if you catch an error.
import Combine
func someFunction(of i: Int) throws -> AnyPublisher<Int, Error> {
return Just(i + 1)
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
}
let upstream: AnyPublisher<Int, Error> = Just(100)
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
upstream
.flatMap({ i -> AnyPublisher<Int, Error> in
do {
return try someFunction(of: i).eraseToAnyPublisher()
} catch {
return Fail(error: error).eraseToAnyPublisher()
}
})
You can write your own tryFlatMap
operator if you like:
extension Publisher {
func tryFlatMap<Pub: Publisher>(
maxPublishers: Subscribers.Demand = .unlimited,
_ transform: @escaping (Output) throws -> Pub
) -> Publishers.FlatMap<AnyPublisher<Pub.Output, Error>, Self> {
return flatMap(maxPublishers: maxPublishers, { input -> AnyPublisher<Pub.Output, Error> in
do {
return try transform(input)
.mapError { $0 as Error }
.eraseToAnyPublisher()
} catch {
return Fail(outputType: Pub.Output.self, failure: error)
.eraseToAnyPublisher()
}
})
}
}
And then use it like this:
upstream
.tryFlatMap { try someFunction(of: $0) }