Combine 框架,從0到1 —— 4.在 Combine 中使用計時器

Ficow發表於2020-09-13

 

本文首發於 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,只需將 TimerscheduledTimer(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

 

相關文章