web-dev-qa-db-fra.com

RxSwift - Debounce/Throttle "inverse"

Disons que j'ai une application de messagerie instantanée qui émet un bip chaque fois qu'un message arrive. Je veux debounce les bips sonores, mais j'aimerais jouer le bip sonore pour le premier message arrivé et non pour les suivants (dans un délai de, disons, 2 secondes).

Un autre exemple pourrait être: mon application envoie des notifications de frappe (pour que l'utilisateur avec lequel je discute puisse voir que je tape un message). Je souhaite envoyer une notification de dactylographie lorsque je commence à taper, mais n'en envoie que de nouvelles toutes les X secondes, de sorte que je n'envoie pas de notification de dactylographie pour chaque caractère saisi.

Est-ce que ça a du sens? Y at-il un opérateur pour cela? Pourrait-il être réalisé avec les opérateurs existants?

Ceci est mon code pour le premier exemple. Je résous maintenant avec debounce, mais ce n'est pas idéal. Si je reçois 1000 messages par intervalles de 1 seconde, le son ne sera pas lu avant que le dernier message n'arrive (j'aimerais lire le son sur le premier).

self.messagesHandler.messages
            .asObservable()
            .skip(1)
            .debounce(2, scheduler: MainScheduler.instance)
            .subscribeNext { [weak self] message in
                    self?.playMessageArrivedSound()
            }.addDisposableTo(self.disposeBag)

Merci!

19
Bruno Koga

Mise à jour pour RxSwift 3 et amélioration de l'opérateur throttle

Avec le nouveau comportement de l'opérateur throtlle, introduit dans RxSwift 3.0.0-beta.1, vous pouvez l'utiliser comme ceci:

    downloadButton.rx.tap
    .throttle(3, latest: false, scheduler: MainScheduler.instance)
    .subscribe(onNext: { _ in
        NSLog("tap")
    }).addDisposableTo(bag)

Ancienne version de answer

Utilisez l'opérateur window puis transformez Observable<Observable<Type>> en flat Observable en utilisant flatMap.

Cet exemple de code imprime 'effleurement' uniquement lors du premier effleurement toutes les 3 secondes (ou si le nombre de prises dépasse 10000).

    downloadButton.rx_tap
    .window(timeSpan: 3, count: 10000, scheduler: MainScheduler.instance)
    .flatMap({ observable -> Observable<Void> in
        return observable.take(1)
    })
    .subscribeNext { _ in
        NSLog("tap")
    }.addDisposableTo(bag)
21
Evgeny Sureev

Window est une excellente solution, mais je trouve l'opérateur de l'exemple plus intuitif et également doté d'un comportement correct.

messagesHandler.messages
               .sample(Observable<Int>.timer(0.0, period: 2.0, scheduler: MainScheduler.instance))
               .subscribeNext { [weak self] message in
                    self?.playMessageArrivedSound()
               }.addDisposableTo(self.disposeBag)

La manette des gaz ne fait pas ce que je pensais. 

Pour les personnes qui trouvent également l'accélération est trop déroutant: 

"throttle ne transmettra un événement que lorsque l'observateur source aura cessé d'envoyer des événements pour la période spécifiée. Cela ne fonctionne pas bien avec la livraison normale d'événements" pour plus de détails

Dans ce cas, le filtre souhaité est 

sample(Observable<Int>.timer(0.0, period: 2.0, scheduler: MainScheduler.instance))
1
Guy Kahlon