当take(_:) 完成时,Observable 链被释放。但是,如果 flatMapLatest 闭包内的 Observable 完成,则链不会被释放,因为 startCountDown 尚未完成。 flatMapLatest observable 在它订阅的所有 observable 完成之前不会完成。所以解决方案是将 take(_:) 放在 flatMapLatest 中。
视图模型应如下所示:
func startCountDown(counter: Int, trigger: Observable<Void>, scheduler: SchedulerType) -> Observable<Int> {
trigger
.flatMapLatest {
Observable<Int>.timer(.seconds(0), period: .seconds(1), scheduler: scheduler)
.take(counter + 1)
}
}
您在视图控制器中使用上述视图模型,如下所示:
startCountdown(counter: 10, trigger: startButton.rx.tap.asObservable(), scheduler: MainScheduler.instance)
.subscribe(onNext: { time in
print(time)
})
.disposed(by: rx.disposeBag)
严格来说,这是一个计时计时器。它将从 0 变为 counter,然后等待按钮再次被点击。如果在计数时点击按钮,它将重新启动。如果您希望它在完成计数之前忽略水龙头,请改用flatMapFirst。
通过阅读本文了解更多信息:RxSwift's Many Faces of FlatMap
作为奖励,以下是测试视图模型的方法:
final class CountdownTests: XCTestCase {
func test() {
let scheduler = TestScheduler(initialClock: 0)
let trigger = scheduler.createObservable(timeline: "--V---V-|", values: ["V": ()])
let expected = parseEventsAndTimes(timeline: "---012-0123456789|", values: { Int(String($0))! })
let result = scheduler.start(created: 0, subscribed: 0, disposed: 100) {
startCountDown(counter: 9, trigger: trigger, scheduler: scheduler)
}
XCTAssertEqual(result.events, expected[0])
}
}
以上使用我的TestScheduler