Reputation: 61880
Currently I have the following working code:
mainView.saveButton.rx.tap.bind { [weak self] in
if let self = self {
// start indicator
self.viewModel.save() // Completable
.subscribe(onCompleted: { [weak self] in
// completed
}, onError: { error in
// error
})
.disposed(by: self.disposeBag)
}
}.disposed(by: disposeBag)
But I know it is not a good approach (due to nested subscriptions), so I am trying to create working equivalent (now with no success):
mainView.saveButton.rx.tap
.do(onNext: { [weak self] in
// start indicator
})
.flatMapFirst { _ in
self.viewModel.save() // Completable
}
.subscribe(onError: { error in
// error
}, onCompleted: { [weak self] in
// completed
})
.disposed(by: disposeBag)
Subscribe closure is not calling at all. Why?
Upvotes: 1
Views: 1009
Reputation: 33979
The flatMap
won't complete until its source (the button tap) completes. It can't because it has to be ready if the user taps the button again.
The most common way to fix this would be to have your save()
function return a Single<Void>
instead of a Completable
. If you don't want to (or can't) do that, then you can use andThen
to send an event on completion.
Also, you don't want an error to escape the flatMap because that will break the button tap. This means you need to catch
any errors and convert them to next events within the closure. You can do that with materialize()
or catch
and use a dedicated subject. (Check out my ErrorRouter for example.)
Something like this:
let errorRouter = ErrorRouter()
let saveSuccessful = mainView.saveButton.rx.tap
.flatMap { [viewModel] in
viewModel.save()
.andThen(Observable.just(()))
.rerouteError(errorRouter)
}
Observable.merge(
mainView.saveButton.rx.tap.map(to: true),
saveSuccessful.map(to: false)
)
.bind(onNext: { isIndicatorVisible in
// handle indicator
})
.disposed(by: disposeBag)
errorRouter.error
.bind(onNext: { error in
// handle error
})
.disposed(by: disposeBag)
Upvotes: 0