Подтвердить что ты не робот

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)

Спасибо!

4b9b3361

Ответ 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))