This code does not compile on iOS 13 because flatMap is available only in iOS 14. How to extend SubscribeOn to have flatMap operator?
func f1(_ value: Int) -> Future<Int, Error> {
Future { promise in
print("\(Thread.current): f1() value = \(value)")
promise(.success(value 1))
}
}
func f2(_ value: Int) -> Future<Int, Error> {
Future { promise in
print("\(Thread.current): f2() value = \(value)")
promise(.success(value 1))
}
}
let a1 = Just(0)
.subscribe(on: DispatchQueue.global())
.flatMap(f1)
.flatMap(f2)
.receive(on: DispatchQueue.main)
.sink { _ in
print("\(Thread.current): completed")
} receiveValue: { value in
print("\(Thread.current): sink() value = \(value)")
}
UPDATE Here is how my solution looks like now:
extension Publishers.SubscribeOn {
func myFlatMap<P>(_ transform: @escaping (Self.Output) -> P) -> Publishers.FlatMap<P, Publishers.SetFailureType<Self, P.Failure>> where P: Publisher {
Publishers.FlatMap<P, Publishers.SetFailureType<Self, P.Failure>>(
upstream: Publishers.SetFailureType<Self, P.Failure>(upstream: self),
maxPublishers: .unlimited,
transform: transform
)
}
}
CodePudding user response:
There is a flatMap
operator available in iOS 13, but there are more flatMap
operators available in iOS 14.
Specifically, the only flatMap
operator available in iOS 13 requires that the upstream publisher (in your example, Just<Int>
) and the inner publisher (in your example, Future<Int, Error>
) have the same Failure
type. But Just<Int>.Failure
is Never
, while Future<Int, Error>.Failure
is Error
.
In iOS 14, there are three extra overloads of flatMap
for special treatment of three cases:
- when the upstream
Failure
type isNever
, - when the inner
Failure
type isNever
, - and when both the upstream
Failure
and the innerFailure
areNever
.
Your example code falls into the first special case (upstream Failure
is Never
), so it compiles for iOS 14 but not for iOS 13.
You can work around the problem by explicitly transforming your Just
with a setFailureType
operator:
let a1 = Just(0)
.setFailureType(to: Error.self)
.subscribe(on: DispatchQueue.global())
.flatMap(f1)
.flatMap(f2)
.receive(on: DispatchQueue.main)
.sink { _ in
print("\(Thread.current): completed")
} receiveValue: { value in
print("\(Thread.current): sink() value = \(value)")
}
Alternatively, you can use a Result.Publisher
to start out with the necessary Failure
type of Error
. Swift should even be able to deduce it for you:
let a1 = Result.success(0).publisher
.subscribe(on: DispatchQueue.global())
.flatMap(f1)
.flatMap(f2)
.receive(on: DispatchQueue.main)
.sink { _ in
print("\(Thread.current): completed")
} receiveValue: { value in
print("\(Thread.current): sink() value = \(value)")
}