使用RXSwift撸一个倒计时按钮

3,073 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情


前言

今天又来撸RXSwift功能了!

说起倒计时按钮这个功能大家应该都不陌生,在iOS中,有很多方法可以去实现,比如GCD,NSTimer等,按使用情况来说,GCD还是出场机会比较多,毕竟代码量少。

今天要说的主角并不是GCD,而是用RXSwift去实现这个功能。

正赶上公司需求,就顺便用RXSwift去实现一下,看看它到底好不好用。

先声明 咱们使用的版本是

pod 'RxSwift', '~> 5.0'
pod 'RxCocoa', '~> 5.0'

版本比较新,对应以前的版本,RXSwift有语法上的变化,注意


正文

第一步:咱们先定义一个timer

 let timer = Observable<Int>.interval(RxTimeInterval.seconds(1), scheduler: MainScheduler.instance)

在这里先说明一下,我参考过其他人的写法,很多人写定时器的时候容易把 Observable<Int>.intervalObservable<Int>.timer 弄错,这里解释一下

interval:每隔一段时间,发出一个索引数,将发出无数个
timer:在一段延时后,每隔一段时间产生一个元素

如果不是需要延时操作,我们就选择interval

然后第一个参数 RxTimeInterval.seconds(1) 表示的是间隔1秒,在老版本中,这个参数可以直接填1 或者 DispatchTimeInterval.seconds(1) 但是在新的版本中,这么天会有警告,还是改成最新的写法把。

第二个参数 MainScheduler.instance,这里解释一下

MainScheduler其实是对DispatchQueue.main的封装。提供了一些访问方法,包括initinstance(同步)asyncInstance(异步)等,在这里,定时器需要传入在那个线程上,所以我们选择MainScheduler.instance

第二步:声明两个BehaviorRelay

 private let countDownSeconds: Int = 60
 let countDownStopped = BehaviorRelay(value: true)
 let leftTime = BehaviorRelay(value: countDownSeconds)

countDownStoppedleftTime理解起来不用太复杂,就相当与定义了个变量,countDownStopped是初始值为true的BOOL类型,leftTime是初始值为60的Int类型。

别问我为什么要这么做,因为装逼因为帅😎.....

ps : 在以前的版本里 很多都用的不是BehaviorRelay而是 Variable,官方说了,以后都不会支持 Variable,所以用新的不会错。至于为什么,请参考

第三步:关键代码

func countdownTime(){
        // 开始倒计时
        self.countDownStopped.accept(false)
        timer.takeUntil(countDownStopped.asObservable().filter{$0})
            .observeOn(MainScheduler.asyncInstance)
            .subscribe(onNext: { [weak self](event) in
               self!.leftTime.accept(self!.leftTime.value - 1)
               /// UI操作
               
               if (self!.leftTime.value == 0) {
                   print("倒计时结束")
                   self!.countDownStopped.accept(true)
                   self!.leftTime.accept(countDownSeconds)
                   /// UI操作
               }
           }, onError: nil )
           .disposed(by: disposeBag)
    }

当我们点击执行countdownTime时,先修改 countDownStopped为false,然后开始倒计时。

解释: takeUntil(countDownStopped.asObservable().filter{$0})

就是有一个东西观察timer的时候同时观察countDownStopped的值,当countDownStopped的值改变时,就停止timer(重点!!多读几遍)


解释:.observeOn(MainScheduler.asyncInstance)

observeOn 来决定在主线程异步(MainScheduler.asyncInstance)监听这个数据序列


接下来看每次定时器变化时的操作

self!.leftTime.accept(self!.leftTime.value - 1)

定时器每次改变时,将leftTime进行 -1操作

if (self!.leftTime.value == 0)

leftTime为0时,

self!.countDownStopped.accept(true)

countDownStopped变为true

self!.leftTime.accept(countDownSeconds)

同时将leftTime变为60

这样就完成了一个基本的定时操作


如何随时停止呢?

只要执行 countDownStopped.accept(true) 就行,这时定时器就不会继续走了。

结语

至此,倒计时功能就完成了,说实话,学习成本比GCD高上不少,因为网上的文档不是太全,而且RXSwift的使用函数又很多,所以很容易蒙圈。我觉得在学习量比较多的情况下,最好是能自己形成一个套路,封装成代码块,这样就很方便了。