I have two functions with the following signatures:
import Combine
func firstCall() -> Future<Result<Void, Error>, Never> {
return Future { promise in
promise(.success(.success(())))
}
}
func secondCall() -> Future<Result<Void, Error>, Never> {
return Future { promise in
promise(.success(.success(())))
}
}
// Execute 1st call, then if it succeeds, execute the 2nd call
How can I execute the 2nd function only after the 1st one completes successfully?
Ideally, I'm looking to something like this:
executeInSequence([firstCall(), secondCall()])
.onResult( { finalResult in
print(finalResult)
})
Feel free to slightly adjust API signatures if that helps the call site.
More information: one of the calls is actually a converted synchronous method call with a signature of:
func secondSynchronousCall() throws {
}
private func secondCall() -> Future<Result<Void, Error>, Never> {
return Future { [weak self] promise in
do {
try self?.secondSynchronousCall()
promise(.success(.success(())))
} catch {
promise(.success(.failure(error)))
}
}
}
CodePudding user response:
In Combine, Futures are just specialised publishers. Given you deal with publishers, you would do something like this:
let cancellable = firstCall()
.tryMap { result in
try result.get()
}
.flatMap { _ in
secondCall()
}
.tryMap { result in
try result.get()
}
.sink { completion in
print(completion)
} receiveValue: { _ in
print("reveiveValue")
}
You can write it more concisely, however, I would suggest to simplify your Output and Error types first, as already pointed out in the comments:
For example:
func firstCall2() -> Future<Void, Error> {
return Future { promise in
promise(.success(()))
//promise(.failure(MyError()))
}
}
func secondCall2() -> Future<Void, Error> {
return Future { promise in
promise(.success(()))
}
}
and then:
let cancellable2 = firstCall2()
.map(secondCall2)
.sink { completion in
print(completion)
} receiveValue: { _ in
print("reveiveValue")
}