You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用RxSwift实现可重启的倒计时功能

解决RxSwift倒计时可重启且订阅不终止的问题

原代码的核心问题是take(counter + 1)作用于外层序列,导致倒计时结束后整个订阅直接完成终止。要实现点击按钮即可重启、且订阅持续活跃的效果,需要调整序列的结构,把终止逻辑限制在单次倒计时的内部序列中。

修改后的代码

fileprivate let counter = 10
fileprivate let startCountDown = PublishRelay<Void>()

startCountDown
    .flatMapLatest { _ -> Observable<Int> in
        // 每次触发时生成独立的倒计时序列,内部完成不影响外层订阅
        return Observable<Int>.timer(.seconds(0), period: .seconds(1), scheduler: MainScheduler.instance)
            .take(self.counter + 1) // 将take移到内部,仅终止当前单次倒计时
            .map { self.counter - $0 } // 可选:如需从counter倒计数到0,添加此map
    }
    .subscribe(onNext: { time in
        print(time)
    }, onCompleted: {
        // 外层订阅不会触发此回调,因为startCountDown是永不自动完成的PublishRelay
        print("Completed")
    })
    .disposed(by: rx.disposeBag)

关键调整说明

  • 把take移到内部序列:原代码中take作用于外层,会直接终止整个订阅。现在将其放在flatMapLatest返回的内部Observable里,每次倒计时结束仅终止当前的单次序列,外层的startCountDown订阅始终保持活跃,等待下一次触发。
  • 利用flatMapLatest的特性:每次点击按钮触发startCountDown时,会自动取消上一轮未完成的倒计时,立即启动新的倒计时,完美实现“重启”逻辑。
  • 可选倒计数转换:如果需要显示从counter到0的倒计数值(比如10、9...0),添加map { self.counter - $0 }即可;若保留原代码的0到10递增输出,可移除该map。

验证逻辑

  • 首次点击:正常完成一轮倒计时,订阅保持活跃。
  • 中途点击:当前倒计时被中断,立刻启动新的一轮倒计时。

内容的提问来源于stack exchange,提问作者ChanSeul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 07:45:24