iosswiftobservablerx-swift

RxSwift: How to create an observable using two other observables (one of which relies on the other)?


I'm new to RxSwift and just inherited an old codebase (none of the original developers are around). I'm trying not to make many/any tweaks to the architecture (MVVM).

In the code, each view controller has a view model, and each view model exposes Rx Drivers that the view controllers can use to update their UI (genericized driver example below):

lazy var imageToDisplay: Driver<UIImage?> = {
        Observable.combineLatest(observableAPICall1(), observableAPICall2())
            .map { [unowned self] payload1, payload2 in
                if payload1 == nil || payload2 == nil {
                    return UIImage(named: "default")!
                } else {
                    return payload1.image
                }
            }
            .asDriver(onErrorJustReturn: nil)
}()

Within the view model driver code, we make API calls via methods that return observables (ex: observableAPICall1() seen above).

For my current task, I'm adding a new API call that requires some information about the user before it can be called (let's say the API call is getGiftIdeasForUser(givenBirthday: Date) and the required info is the user's birthday).

Now, here's the part I'm struggling with: both the API call and the user's profile (the object that stores the birthday) are observables. So, how can I structure my code / API call to ensure I have the user's birthday before making said API call?

In other words, is there a way to chain things so that I get the user profile observable first, then hit the getGiftIdeasForUser() observable API after?

Apologies in advance if I'm thinking about this the wrong way ... still wrapping my head around Rx. Thanks.


Solution

  • The most basic solution would be something like this:

    struct User {
        let birthday: Date
    }
    struct GiftIdea { }
    
    func example(userProfile: Observable<User>, getGiftIdeasForUser: @escaping (Date) -> Observable<[GiftIdea]>) -> Observable<[GiftIdea]> {
    
        userProfile
            .map { $0.birthday }
            .flatMap { getGiftIdeasForUser($0) }
    
    }
    

    However, there are several different flatMap functions and the one you should use depends on context you didn't provide. Here is an article explaining the different flatMap operators and under what context you would use them in: RxSwift's Many Faces of FlatMap