0

I have the following code:

import Combine

func login() -> Future<Token, Error> { ... }
func updateImage() -> Future<Status, Never> { ... }

login()
    .flatMap { response -> Future<Status, Error> in
        // handle response and save token locally
        return updateImage()
    }
    .sink(receiveCompletion: { error in
        ... //handleError
    }, receiveValue: { response in
        ... // handle response and a different error
    })
    .store(in: ...)

I want to join login() and updateImage() into a sequence. However, I found that zip is only for parallel requests. I need a way to chain them sequentially, and I am not sure if map, tryMap, or mapError methods can help me achieve that. I need to not only transform but also handle the response data and errors from each function.

How to solve this issue?

Gargo
  • 1,135
  • 1
  • 10
  • 21
  • I created "nested" requests but Combine (and other libraries with `Futures`) usually also provide a syntax when you just call `future.someHandler(...).someHandler2(...).someHandler3(...)...` - without of nesting. Or if Combine doesn't allow that? – Gargo Jun 16 '23 at 05:49
  • tried flatMap - now I get error `flatMap` is not available in iOS 13 – Gargo Jun 16 '23 at 05:54
  • That can't be true with the code you posted. What are you flat mapping it to? Are you trying to flatmap to a publisher that `Never` fails? That would indeed call [an overload of `flatMap`](https://developer.apple.com/documentation/combine/future/flatmap(maxpublishers:_:)-61pe1) that isn't available in iOS 13. – Sweeper Jun 16 '23 at 06:00
  • Yes, `flatMap` only works with same error types prior to iOS 14. Do you have different error types? If so, [edit] the question to reflect that. – Sweeper Jun 16 '23 at 06:07
  • @Sweeper I'm very sorry I really use `Never` in the second call. But how to deal with it in iOS 13? – Gargo Jun 16 '23 at 06:10

1 Answers1

1

In iOS 14+, there is a new overload of flatMap that allows you flat map to a publisher that Never fails, so you just need to change the explicit return type of your closure to match the type that updateImage returns:

.flatMap { response -> Future<Status, Never> in // change "Error" to "Never"

Prior to iOS 14, you would need to use setFailureType(to:):

.flatMap { response -> Publishers.SetFailureType<Future<Status, Never>, Error> in
    // ...
    return updateImage().setFailureType(to: Error.self)
}

If you don't like such a long type name, use AnyPublisher:

.flatMap { response -> AnyPublisher<Status, Error> in
    // ...
    return updateImage().setFailureType(to: Error.self).eraseToAnyPublisher()
}
Sweeper
  • 213,210
  • 22
  • 193
  • 313