Joakim Sjöstedt
Joakim Sjöstedt

Reputation: 948

How do I flatMap two singles?

I have an observable that looks like this:

func getParameters() -> Single<[ParameterModel]?> {
    do {
        loading.accept(allParameters.isEmpty)
        return try parameterService.getParameters()
            .do(onSuccess: { [weak self] parameters in
                self?.loading.accept(false)
                self?.content.accept(parameters?.compactMap { $0 }
                                                .compactMap { TechnicianParameterTableViewCellViewModel(parameter: $0) } ?? [])
            })
    } catch { return Single.error(error) }
}

The important part is where it compactMaps into a cell. This works as expected. But I also have another observable that looks like this:

func getSingleOrDoubleDoor() -> Single<SingleOrDoubleDoor?> { //SingleOrDoubleDoor is an enum
    do {
        return try parameterService.getSingleOrDoubleDoor()
    } catch {
        return Single.error(error)
    }
}

Now, I would like to sort of merge getSingleOrDoubleDoor() into getParameters() so that I can access the values of both observables in onSuccess. I want to use the result sort of like this:

.compactMap { TechnicianParameterTableViewCellViewModel(parameter: $0, isSingleOrDouble: $1) } ?? [])

Not being an expert on Rx I still assume that this is done using .flatMap{}. Sort of like:

...return try parameterService.getParameters().flatMap { _ in getSingleOrDoubleDoor() }...

But this gives me an error:

Cannot convert value of type '([ParameterModel]?) -> Single<SingleOrDoubleDoor?>' (aka '(Optional<Array>) -> PrimitiveSequence<SingleTrait, Optional>') to expected argument type '([ParameterModel]?) throws -> PrimitiveSequence<SingleTrait, [ParameterModel]?>'

Tried changing the return expression but it still wouldn't take. Not sure how to make this happen.

Upvotes: 1

Views: 476

Answers (1)

Claudio
Claudio

Reputation: 5203

Since your methods don't accept parameters, I'll assume they don't depend on each other. If so, you should use the zip method like this:

Single
   .zip(getParameters(), getSingleOrDoubleDoor())
   .compactMap { TechnicianParameterTableViewCellViewModel(parameter: $0, isSingleOrDouble: $1) } ?? [])

The zip method will trigger the compactMap when both methods return a value. Flatmap has a different purpose, it is usually used when we need to call methods sequentially, meaning the next call needs data from the previous one.

Upvotes: 1

Related Questions