Search code examples
rx-swiftrx-cocoa

RxSwift trigger observable on button tap


I am creating a custom observable that will present a UIAlertController which would like to trigger an API Call when pressed. However, I can't seem to get the Alert to pop unless I manually subscribe to it. Is there a way to get this triggered from the viewModel?

MyController.swift

class MyController: UIViewController {
    @IBOutlet weak var nextBarButton: UIBarButtonItem!

    var viewModel: ViewModel!

    override func viewDidLoad() {
        super.viewDidLoad()


        viewModel = ViewModel( nextBarButton.rx.tap.asDriver(), alertController()asDriver(onErrorJustReturn: ""))
    }

    func alertController() -> Observable<String> {
        return Observable.create { [weak alert = self] observer in
            guard let alert = alert else {
                observer.on(.completed)
                return Disposables.create()
            }

            let alertVc = UIAlertController(title: "My Title", message: "My Message", preferredStyle: .alert)
            let submit = UIAlertAction(title: "Continue", style: .default) { _ in
                observer.onNext("Test")
                observer.on(.completed)
            }
            let cancel = UIAlertAction(title: "Cancel", style: .cancel) { _ in
                observer.on(.completed)
            }
            alertVc.addAction(cancel)
            alertVc.addAction(submit)
            alert.present(alertVc, animated: true, completion: nil)

            return Disposables.create {
                alertVc.dismiss(animated: true, completion: nil)
            }
        }
    }
}

ViewModel.swift

public final class ViewModel {
    init(_ manager: SessionManager, _ trigger: Driver<Void>, _ alert: Driver<String>) {
        let _ = trigger.withLatestFrom(alert)
            .flatMap { text in
                return manager.rx
                    .request(urlRequest: Api.test)
                    .retry(3)
                    .asDriverOnErrorJustComplete()
            }
    }
}

Solution

  • You forgot to subscribe() in your ViewModel and you should flatMapLatest when chaining events from UIButton. It should look like:

    public final class ViewModel {
        init(_ manager: SessionManager, _ trigger: Driver<Void>, _ alert: Driver<String>) {
            let _ = trigger.flatMapLatest{ alert }
                .flatMap { text in
                    return manager.rx
                        .request(urlRequest: Api.test)
                        .retry(3)
                        .asDriverOnErrorJustComplete()
                }
                .subscribe()
        }
    }