2016-02-16 13 views
19

Diciamo che ho un'applicazione di messaggistica istantanea che riproduce un segnale acustico ogni volta che arriva un messaggio. Voglio fare il debounce bip, ma mi piacerebbe suonare il segnale acustico per il primo messaggio arrivato e non per i seguenti (in un intervallo di, diciamo, 2 secondi).RxSwift - Debounce/Throttle "inversa"

Un altro esempio potrebbe essere: la mia applicazione invia a digitare le notifiche (in modo che l'utente che sto chiacchierando con può vedere che sto scrivendo un messaggio). Voglio inviare una notifica di digitazione quando comincio a digitare, ma invio solo nuovi in ​​intervalli di X secondi, quindi non invio una notifica di digitazione per ogni carattere che digito.

Ha senso? C'è un operatore per questo? Potrebbe essere raggiunto con gli operatori esistenti?

Questo è il mio codice per il primo esempio. Sto risolvendolo ora con debounce, ma non è l'ideale. Se ricevo 1000 messaggi in intervalli di 1 secondo, non suonerà il suono fino a quando non arriva l'ultimo messaggio (mi piacerebbe suonare il suono sul primo).

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

Grazie!

+0

Questa è una buona spiegazione https://medium.com/@dkhuong291/throttle-vs-debounce-in-rxswift-86f8b303d5d4 – onmyway133

risposta

20

aggiornato per RxSwift 3 e migliorato throttle operatore

Con il nuovo comportamento del throtlle dell'operatore, introdotto nel RxSwift 3.0.0-beta.1, è possibile utilizzarlo proprio così:

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

vecchia versione di risposta

Usa window operatore e poi trasformare Observable<Observable<Type>> al piatto Observable utilizzando flatMap.

Questo campione stampe codice 'tap' solo per il primo tap in ogni 3 secondi finestre (oppure se count rubinetto supera 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) 
+0

Sono Attualmente sto usando una soluzione simile, ma sento che c'è margine di miglioramento. Mi piacerebbe evitare il doppio abbonamento. Grazie per aver risposto! –

+3

Ci sono sicuramente margini di miglioramento. Ora funziona senza doppio abbonamento. –

1

Window è una grande soluzione, ma trovo l'operatore del campione più intuitiva e anche con un comportamento corretto.

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

L'operazione di accelerazione non funziona come pensavo.

Per le persone che anche trovare acceleratore è troppo confusa:

"acceleratore sarà solo in avanti di un evento una volta la fonte osservabile ha smesso di inviare gli eventi per il periodo di tempo specificato Questo non funziona bene con regolare distribuzione degli eventi" for more details.

In questo caso, il filtro che si desidera è

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