RxSwift - Debounce/Throttle "inverse"
Скажем, у меня есть приложение для обмена мгновенными сообщениями, которое воспроизводит звуковой сигнал каждый раз, когда приходит сообщение. Я хочу debounce
звуковые сигналы, но я бы хотел воспроизвести звуковой сигнал для первого сообщения, а не для следующих (в секундах, скажем, 2 секунды).
Другим примером может быть: мое приложение отправляет ввод уведомлений (так что пользователь, с которым я общаюсь, может видеть, что я набираю сообщение). Я хочу отправить уведомление о наборе текста, когда я начну вводить текст, но только отправлю новые в течение X-секундных интервалов, поэтому я не отправляю уведомление о наборе для каждого символа, который я печатаю.
Это имеет смысл? Есть ли для этого оператор? Может ли быть достигнуто с существующими операторами?
Это мой код для первого примера. Теперь я решаю это с помощью debounce
, но это не идеально. Если я получаю 1000 сообщений с интервалом в 1 секунду, он не будет воспроизводить звук до тех пор, пока не поступит последнее сообщение (я хотел бы воспроизвести звук на первом).
self.messagesHandler.messages
.asObservable()
.skip(1)
.debounce(2, scheduler: MainScheduler.instance)
.subscribeNext { [weak self] message in
self?.playMessageArrivedSound()
}.addDisposableTo(self.disposeBag)
Спасибо!
Ответы
Ответ 1
Обновлен для RxSwift 3 и улучшен оператор throttle
С новым поведением оператора throtlle
, введенным в RxSwift 3.0.0-beta.1, вы можете использовать его так:
downloadButton.rx.tap
.throttle(3, latest: false, scheduler: MainScheduler.instance)
.subscribe(onNext: { _ in
NSLog("tap")
}).addDisposableTo(bag)
Старый вариант ответа
Используйте оператор window
, а затем преобразуйте Observable<Observable<Type>>
в flat Observable
с помощью flatMap
.
Этот пример кода печатает "отвод" только для первого касания каждые 3 секунды окна (или если количество отводов превышает 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)
Ответ 2
Окно - отличное решение, но я считаю, что оператор образца более интуитивно понятен, а также с правильным поведением.
messagesHandler.messages
.sample(Observable<Int>.timer(0.0, period: 2.0, scheduler: MainScheduler.instance))
.subscribeNext { [weak self] message in
self?.playMessageArrivedSound()
}.addDisposableTo(self.disposeBag)
Операция дроссельной заслонки не делает то, что я думал, что нужно.
Для людей, которые также считают, что дроссель слишком запутан:
"дроссель будет только пересылать событие, как только наблюдаемый источник прекратит отправку событий за указанный период времени. Это не работает с обычной доставкой событий" для более подробной информации.
В этом случае требуемый фильтр
sample(Observable<Int>.timer(0.0, period: 2.0, scheduler: MainScheduler.instance))