As is the case with both Reactive and non-Reactive iOS projects alike, if you have a UI element (e.g. a button or a table view cell that is being selected) that pushes a view controller onto the navigation stack, if there's lag for some reason (especially on older devices) repetitive taps can result in duplicate pushes and thus bad UX.
Normally you could disable the element after the first tap.
For example:
@IBAction func myButtonTap() {
button.isEnabled = false
doTheRestOfTheAction()
}
I am relatively new to RxSwift. I am trying to figure out an appropriate Reactive way to implement this to fix a few bugs in my app where views get pushed repetitively.
Some thoughts:
Could use debounce
or throttle
but seems like a bandaid and won't necessarily fix every situation.
I'm currently thinking that the best way is to dispose of the subscription once the expected event has occurred.
let disposable = tableView.rx.itemSelected
.subscribe(onNext: { [weak self] indexPath in
self?.performSegue(withIdentifier: "MySegueIdentifier", sender: self)
})
...
func prepareForSegue() {
myDisposable.dispose()
finishPrepareForSegue()
}
Although if you want to unsubscribe inside the subscribe block, the compiler complains about using a variable inside its own initial value, which makes sense. I suppose there are workarounds but I wonder, is there a better way? Maybe a Reactive operator I'm missing?
Tried searching around for similar examples but the results were limited.
Thanks
EDIT: perhaps the takeUntil
operator?
Not the only solution, but this seems to be working well at least for the case of pushing upon table view selection. It uses the
takeUntil
operator to stop the eventsAlthough note that if you can return to view controller then you'd have to resubscribe, perhaps by moving the subscription to
viewDidAppear
. Maybe there's a more efficient method though that doesn't require re-subscription.Another option is
take(1)
instead oftakeUntil(…)
, but it would still require re-subscription upon returning to the view controller.