ios - rxcocoa - rxswift tutorial
RxSwift-Debounce/Throttle “inverso” (2)
Digamos que tengo una aplicación de mensajería instantánea que emite un pitido cada vez que llega un mensaje. Quiero debounce
los pitidos, pero me gustaría reproducir el pitido cuando llegó el primer mensaje y no para los siguientes (en un lapso de tiempo de, por ejemplo, 2 segundos).
Otro ejemplo podría ser: mi aplicación envía notificaciones de escritura (para que el usuario con el que estoy chateando pueda ver que estoy escribiendo un mensaje). Quiero enviar una notificación de escritura cuando empiezo a escribir, pero solo envío mensajes nuevos en intervalos de X segundos, por lo que no envío una notificación de escritura para cada carácter que escribo.
¿Esto tiene sentido? ¿Hay un operador para eso? ¿Podría lograrse con los operadores existentes?
Este es mi código para el primer ejemplo. Lo estoy resolviendo ahora con debounce
, pero no es lo ideal. Si recibo 1000 mensajes en intervalos de 1 segundo, no se reproducirá el sonido hasta que llegue el último mensaje (me gustaría reproducir el sonido en el primero).
self.messagesHandler.messages
.asObservable()
.skip(1)
.debounce(2, scheduler: MainScheduler.instance)
.subscribeNext { [weak self] message in
self?.playMessageArrivedSound()
}.addDisposableTo(self.disposeBag)
¡Gracias!
Window es una gran solución, pero me parece que el operador de muestra es más intuitivo y también con el comportamiento correcto.
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 operación del acelerador no hace lo que pensé que debería hacer.
Para las personas que también encuentran acelerador es demasiado confuso:
"el acelerador solo reenviará un evento una vez que la fuente observable haya dejado de enviar eventos durante el período de tiempo especificado. Esto no funciona bien con la entrega regular de eventos" para más detalles .
En este caso, el filtro que desea es
sample(Observable<Int>.timer(0.0, period: 2.0, scheduler: MainScheduler.instance))
Actualizado para RxSwift 3 y operador de throttle
mejorado
Con el nuevo comportamiento del operador de throtlle
, introducido en RxSwift 3.0.0-beta.1, puede usarlo así:
downloadButton.rx.tap
.throttle(3, latest: false, scheduler: MainScheduler.instance)
.subscribe(onNext: { _ in
NSLog("tap")
}).addDisposableTo(bag)
Antigua versión de respuesta.
Use el operador de window
y luego transforme Observable<Observable<Type>>
en Flat Observable
usando flatMap
.
Este código de ejemplo imprime ''toque'' solo para el primer toque en cada ventana de 3 segundos (o si el número de botones supera los 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)