本文首發於 Ficow Shen's Blog,原文地址: Combine 框架,從0到1 —— 4.在 Combine 中使用計時器。
內容概覽
- 前言
- 使用計時器執行週期性的工作
- 將計時器轉換為計時器釋出者(
Timer.TimerPublisher
) - 總結
前言
計時器是蘋果開發者常用的功能。如果你的應用使用 Foundation
框架中的計時器 Timer
來週期性地執行某些操作,你可以用 Combine
簡化這些程式碼。
現在,讓我們來學習如何使用 Combine
處理計時器,並將已有的計時器處理程式碼遷移到 Combine
。
使用計時器執行週期性的工作
對於 iOS
開發人員而言,以下程式碼一定非常眼熟:
var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
self.myDispatchQueue.async() {
self.myDataModel.lastUpdated = Date()
}
}
}
以上程式碼使用 scheduledTimer(withTimeInterval:repeats:block:)
來實現每秒鐘在 myDispatchQueue
中更新 self.myDataModel.lastUpdated
的功能。
將計時器轉換為計時器釋出者(Timer.TimerPublisher
)
要將以上程式碼遷移到 Combine
,只需將 Timer
(scheduledTimer(withTimeInterval:repeats:block:)
的返回值) 替換為 Timer.TimerPublisher
。呼叫 Timer. publish(every:tolerance:on:in:options:)
方法即可建立一個釋出者。
每次底層的計時器(Timer
)觸發時,釋出者都會發出一個新的日期(Date
)例項,該日期代表計時器觸發的瞬間。然後,你可以將 Combine
操作符應用到這個日期例項上,最終將這個釋出者和一個訂閱者(如:sink(receiveValue:)
或 assign(to:on:)
)連線。
由於
Timer.TimerPublisher
遵從ConnectablePublisher
協議,因此在您顯式地連線之前,它不會產生任何元素。為此,可以通過手動呼叫connect()
或使用autoconnect()
運算子在訂閱者連線時自動連線來實現。關於ConnectablePublisher
的用法,可以參考 這篇文章。
下一個示例將展示如何使用 Timer.TimerPublisher
替換上一個示例。它使用 Combine
的操作符來完成上一個示例中的閉包中的操作:
var cancellable: Cancellable?
override func viewDidLoad() {
super.viewDidLoad()
cancellable = Timer.publish(every: 1, on: .main, in: .default)
.autoconnect()
.receive(on: myDispatchQueue)
.assign(to: \.lastUpdated, on: myDataModel)
}
在這個例子中,Combine
操作符替換了上一個示例的閉包中的所有行為:
receive(on:options:)
操作符確保了後續操作在指定的排程佇列中執行,它替代了前面用到的async()
呼叫;assign(to:on:)
操作符通過鍵路徑來更新資料模型的lastUpdated
屬性;
使用 Combine
來簡化你的程式碼時,你會發現 Timer.TimerPublisher
會產生新的 Date
例項作為其輸出型別。而第一個示例的閉包是將 Timer
本身作為其引數,因此它必須手動建立新的 Date
例項。
總結
使用 Combine
來簡化你的計時器程式碼時,你會發現:
- 程式碼易讀性明顯提升;
- 執行緒切換變得更簡單;
- 資料模型的更新可以通過鍵路徑(
key path
)來簡化;
朋友,行動起來吧!把現有專案中的舊程式碼重構成使用 Combine
的程式碼~
本文內容來源:
Replacing Foundation Timers with Timer Publishers