如何在RxSwift中检测可观察对象在特定时间内是否未发出任何事件 [英] How to detect if a observable has not emitted any events for specific time in RxSwift
问题描述
我试图检测一个可观察对象(我的案例 button.rx.tap )是否没有发出任何值(例如3秒钟).如果是,我想更新用户界面.到目前为止,这是我的尝试:
I am trying to detect if a observable(my case button.rx.tap) has not emitted any value for say like 3 seconds. If yes, I would like to update the user interface. Here is my attempt so far:
Observable<Int>.interval(3, scheduler: MainScheduler.instance)
.takeUntil(button.rx.tap) // I know take until will stop the timer sequence
.subscribe({ event in
print(event)
UIView.animate(withDuration: 0.4, animations: {
if let number = event.element {
let scale: CGFloat = number % 2 == 0 ? 1.5 : 1.0
self.button.transform = CGAffineTransform(scaleX: scale, y: scale)
}
})
})
.addDisposableTo(disposeBag)
我的目标是每当未点击按钮三秒钟时,就对视图进行动画处理.我已经尝试过 scan , distinctUntilChanged 和 debounce ,但是我遇到的大多数组合运算符仅在可观察对象发出某项时才发出该项.非常感谢您的帮助.
My goal is to animate the view whenever the button is not tapped for three seconds. I have tried scan, distinctUntilChanged and debounce but most combining operators I have encountered will emit items only when an item is emitted by a observable. Any help is much appreciated.
推荐答案
enum Event {
case tap
case timeout
}
let tapOrTimeout = button.rx.tap
.map { _ in Event.tap }
.timeout(3, scheduler: MainScheduler.instance)
.catchErrorJustReturn(.timeout)
Observable.repeatElement(tapOrTimeout).concat()
.subscribe(onNext: { event in
switch event {
case .tap: tapHandler()
case .timeout: callForAttention()
}
})
-
如果3秒钟内没有事件发生,
-
timeout(_:scheduler:)
将引发错误. -
catchErrorJustReturn(_:)
会将错误转换为.timeout
事件 - 在这一点上,如果可观察的超时,它也会完成,因此此后什么也不会发生.我们首先使用
Observable.repeatElement(_:).concat()
创建一个Observable<Observable<Event>>
,然后连接内部可观察对象.在我们的情况下,这意味着我们将订阅第一个,如果第一个完成,则重新订阅相同的可观察对象. timeout(_:scheduler:)
will raise an error if no event comes out of the chain within 3 seconds.catchErrorJustReturn(_:)
will transform the error into a.timeout
event- at this point, if the observable times out, it will also complete, hence nothing will happen afterward. Using
Observable.repeatElement(_:).concat()
we first create anObservable<Observable<Event>>
and then concatenate inner observables. Which in our case means that we'll subscribe to the first, and the resubscribe to the same observable if the first completes.
如果我们希望只播放一次callForAttention()
动画,则可以执行以下操作
If we had prefer to only play the callForAttention()
animation once, we could have done the following
let tap = button.rx.tap
.map { _ in Event.tap }
let tapOrTimeout = tap
.timeout(3, scheduler: MainScheduler.instance)
.catchErrorJustReturn(.timeout)
Observable.of(tapOrTimeout, tap).concat()
.subscribe(onNext: { /* same as above */})
这样,我们首先超时,但仅在发生轻击时才发出事件.
This way, we first timeout, but then only emit an event when a tap occurs.
这篇关于如何在RxSwift中检测可观察对象在特定时间内是否未发出任何事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!