[RxSwift] 使用RxSwift在畫面上呈現倒數功能
我們需要一個label來顯示目前的秒數,以及一個變數儲存我們做出來的倒數計時器
//倒數計時label
@IBOutlet weak var timeCounterLabel: UILabel!
//存倒數計時的變數
var timer:Disposable?
在viewModel建立timer秒數的變數,這邊我們設為60秒
class ViewModel{
//在這邊設定秒數
let countDown = BehaviorRelay<Int>(value: 60)
}
將label與viewModel內變數綁定,達到顯示倒數的效果
private func setupTimeCounterLabelBinding(){
guard let viewModel = viewModel else { return }
viewModel.countDown.map({$0.toString()}).bind(to: timeCounterLabel.rx.text).disposed(by: disposeBag)
}
這邊我們將timer的創建包成一個function,在viewDidLoad時執行
我們根據viewModel內的countDown變數決定倒數幾秒,並設定一個timer延遲0秒,每過1秒執行一次onNext,設定在主執行緒執行
當timer收到0時執行onCompleted,並且在onCompleted讓viewModel內變數接收到0,並且彈出一個alertView
private func setupTimerCountDown(){
//根據viewModel內的countDown變數決定倒數幾秒
guard let viewModel = viewModel else { return }
let count = viewModel.countDown.value
//設定一個timer延遲0秒,每過1秒執行一次onNext,設定在主執行緒
timer = Observable<Int>.timer(.seconds(0), period: .seconds(1), scheduler: MainScheduler.instance)
.map{return count - $0}//利用map轉換型態
.take(until: {($0 == 0) })//當時間到0時停止
.subscribe(onNext: { timePassed in
guard let viewModel = self.viewModel else { return }
viewModel.countDown.accept(timePassed)
}, onCompleted: {
guard let viewModel = self.viewModel else { return }
viewModel.countDown.accept(0)//若沒設的話label會停在1秒
//完成時跳出彈出式視窗
self.showCustomAlertWithIcon(message: "時間到", buttonTitle: "確認"
, cancelAcction: { self.dismiss(animated: true, completion: nil)})
//讓此頁消失
})
}
在viewDidLoad時執行
override func viewDidLoad() {
super.viewDidLoad()
setupTimeCounterLabelBinding()
setupTimerCountDown()
}
最後則是在跳頁面之後要將timer回收。若沒做到這步的話會在背景繼續倒數。
override func viewWillDisappear(_ animated: Bool) {
timer?.dispose()
}