0

I would like to have an Observable that while debounced (in the time frame where we are still not emitting the value) something else will happen, for example show a spinner.

So in my code example I only reference my view AFTER the value is emitted..

observable.debounce(0.3, scheduler: MainScheduler.instance).do(onNext: { spinner in 
    spinner.stop() //here I set it to stop, I want to run spinner.start() while we are in the debounce area
}).subscribe().disposedBy(disposeBag)

I thought this question might fit my needs but not sure if it is exactly what I ask for: RxSwift - Debounce/Throttle "inverse"

Eyzuky
  • 1,843
  • 2
  • 22
  • 45

2 Answers2

1

As far as I understand the question, the goal is to trigger some action for the timeframe of debouncing/throttling.

It is relatively straightforward to do for throttle (i.e. emitting at most once per timeframe): basically use .window() operator, hang the desired action onto it, and then use the result of .window() for actual throttling.

With debounce (i.e. emitting once after upstream did not emit for a given timeframe), it seems to be complex but probably also doable.

Maxim Volgin
  • 3,957
  • 1
  • 23
  • 38
  • Well it might happen many times.. it is a server request, that if it is executing I want the view to be hidden – Eyzuky Oct 10 '18 at 11:50
  • So you basically want to hide the view while every request is in progress and show it again once a response has arrived? How does debouncing fit into all this, do you fire requests in parallel? – Maxim Volgin Oct 10 '18 at 11:53
  • hmm it is a generic question, the view is hidden is just an example. For the example of server request it could be showing a spinner while debounced.. – Eyzuky Oct 10 '18 at 11:56
  • Use case is still unclear, especially the debouncing part. Just a wild guess, would http://rxmarbles.com/#sample be applicable in your case? – Maxim Volgin Oct 10 '18 at 11:58
  • Use case is just not relevant. I want to know if I could do it or not.. But I will definitely look into your link and update :) thanks – Eyzuky Oct 10 '18 at 11:59
  • Ah, you updated the question - now I think I do understand what you mean. I updated my answer for throttle, will need to think more about debounce. – Maxim Volgin Oct 10 '18 at 12:16
  • Windows seems like the correct thing! will this guarantee that the last emitted value will be triggered? because that is why I used debounce – Eyzuky Oct 10 '18 at 12:17
  • I don't understand how to use it though – Eyzuky Oct 10 '18 at 12:35
  • .last()/.takeLast() for every sequence .window() produces (provided you need the last one and not the first one) and then .concatMap() them together. – Maxim Volgin Oct 10 '18 at 14:17
1

It actually does matter whether you are making a network request or using debounce, because a network request would be done using flatMap and is an independent observable. Here is some sample code that will animate an activity indicator while the network request is in flight:

class ViewController: UIViewController {

    @IBOutlet weak var button: UIButton!
    @IBOutlet weak var activityIndicator: UIActivityIndicatorView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let _activityIndicator = activityIndicator! // to avoid dealing with self.
        button.rx.tap
            .flatMapLatest { () -> Observable<Int> in
                let request = Observable<Int>.timer(5.0, scheduler: MainScheduler.instance)
                return Observable.using({ ActivityIndicatorAnimator(_activityIndicator) }, observableFactory: { _ in request })
            }
            .subscribe()
            .disposed(by: bag)
    }

    let bag = DisposeBag()
}

class ActivityIndicatorAnimator: Disposable {
    init(_ spinner: UIActivityIndicatorView) {
        self.spinner = spinner
        spinner.startAnimating()
    }

    func dispose() {
        spinner.stopAnimating()
    }

    let spinner: UIActivityIndicatorView
}

The above uses a timer to simulate a network request. The using operator will create a resource when the observable starts and dispose of the resource when the observable completes. The ActivityIndicatorAnimator resource starts the animation when the resource is created and stops it when the resource is disposed.

The RxSwift repository has a more complex example called ActivityIndicator that maintains a count of how many times it was started and stopped and can be used to monitor several network requests.

Daniel T.
  • 32,821
  • 6
  • 50
  • 72
  • This is beautiful. I learn from it a lot. I do not think it answers the question directly but it does give insights of how to use different approaches to solve the same problem. Marking as fav – Eyzuky Oct 11 '18 at 07:19