定時器可以設(shè)置按固定周期執(zhí)行某個操作。iOS 中主要有 3 種定時器,本文先講解第一種 Timer。
使用
- iOS 10 之后下面的方法不會出現(xiàn)循環(huán)引用的問題,推薦使用。
// 自動執(zhí)行的Timer
// 參數(shù)一:時間間隔,參數(shù)二:是否重復(fù)執(zhí)行
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (timer) in
// 定期執(zhí)行的代碼
print("Hello World")
}
// 需要手動開啟的Timer
let timer = Timer(timeInterval: 2.0, repeats: true) { (timer) in
// 定期執(zhí)行的代碼
print("Hello World")
}
RunLoop
- 用來處理事件的循環(huán),保持程序持續(xù)運行,App 啟動后會開啟一個主線程,主線程啟動時會運行一個對應(yīng)的 RunLoop,RunLoop 保證主線程不會被銷毀,從而保證了程序的持續(xù)運行。
- RunLoop 工作模式有 5 種,常見模式有以下 3 種:
-
default:默認(rèn)模式。 -
tracking:界面跟蹤模式。 -
common:通用模式,前面 2 種的結(jié)合。
-
- 將 Timer 添加到 RunLoop 后會自動開始工作。
// 界面發(fā)生拖拽就會停止執(zhí)行
RunLoop.current.add(timer, forMode: .default)
// 界面拖拽才會執(zhí)行
RunLoop.current.add(timer, forMode: .tracking)
// 上面兩種模式的結(jié)合,常用
RunLoop.current.add(timer, forMode: .common)
暫停與重啟
// 暫停
timer.fireDate = Date.distantFuture
// 重啟
timer.fireDate = Date.distantPast
銷毀
invalidate:阻止 Timer 再次觸發(fā)并請求將其從 RunLoop 中刪除,因此這種方式停止后無法讓其重新開始工作。
timer.invalidate()
案例:倒計時
import UIKit
class ViewController: UIViewController {
// 倒計時總時長(秒)
var count = 5
// 定時器
var timer: Timer!
// UILabel+UITapGestureRecognizer比UIButton好
lazy var label: UILabel = {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 30))
label.center = view.center
label.text = "獲取倒計時"
label.textAlignment = .center
label.isUserInteractionEnabled = true
label.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleCount)))
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(label)
}
@objc func handleCount() {
// 倒計時過程中不允許點擊
label.isUserInteractionEnabled = false
// 創(chuàng)建Timer,每隔1s執(zhí)行一次
timer = Timer(timeInterval: 1.0, repeats: true) { _ in
// 顯示倒計時
self.label.text = "\(self.count)"
// 計時減1
self.count -= 1
// 當(dāng)計時為0時
if self.count == 0 {
// 停止計時
self.timer.invalidate()
// 改變文字
self.label.text = "重新獲取"
// 允許交互
self.label.isUserInteractionEnabled = true
// 恢復(fù)倒計時總時長
self.count = 5
}
}
// 添加RunLoop,定時器開始工作
RunLoop.current.add(timer, forMode: .common)
}
}