Search code examples
iosswiftrx-swiftflatmap

Can I flatMap into other streams with completables?


I have several completable rx subscriptions in a stream like this:

viewModel?.setupDoorMode().subscribe(onNext: { shouldConnectToDoor in
    if shouldConnectToDoor {
         self.viewModel?.connectAndOpenDoor().subscribe(onCompleted: {
             self.viewModel?.openOrCloseDoor().subscribe().disposed(by: self.disposeBag)
         }).disposed(by: self.disposeBag)
    } else {
         self.viewModel?.openOrCloseDoor().subscribe().disposed(by: self.disposeBag)
    }
}).disposed(by: disposeBag)

I have the feeling that this can be done in a nicer way, like flatMaping the streams into oneanother. But when I try using flatMap I get the error Type '()' cannot conform to 'ObservableConvertibleType'; only struct/enum/class types can conform to protocols. I'm not too familiar with rx to understand that message. Anyway, is there a way to create a more smooth looking stream rather than three subscriptions in a row?


Solution

  • You’re definitely on the right track thinking about flatMap to compose your observables. The thing to note here is that calling .subscribe() returns a Disposable type and calling .disposed(by:) on that disposable returns Void aka () type. You can't compose Voids. You have compose the observables, and THEN you subscribe to the result.

    guard let viewModel = viewModel else { return }
    
    // Combine the observables
    let doorActionObservable = viewModel
        .setupDoorMode()
        .flatMap { /* mind the retain cycle */ shouldConnectToDoor in
            if shouldConnectToDoor {
                return self.viewModel.connectAndOpenDoor()
            } else {
                return self.viewModel.openOrCloseDoor()
            }
        }
    
    // Subscribe to the the resulting observable
    doorActionObservable
        .subscribe()
        .disposed(by: disposeBag)