Swift — 玩玩 Publishers & Subscribers

讓我們使用 Publishers 和 Subscribers 來實作訂閱關係吧!

Jeremy Xue
Jeremy Xue ‘s Blog
6 min readAug 30, 2020

--

✒︎ 前言:

前面寫了許多關於 Combine 在官方文件中的成員描述以及使用方法,然後這次讓我們來實際玩玩其中的成員來製作一些簡單的應用吧!

如果還沒看過前幾篇 Combine 在官方文件中的介紹,也可以先閱讀我以下的幾篇簡單的介紹文章:

✒︎ 目錄

  • Publisher & Subscriber 流程
  • 實作應用介紹
  • 實作訂閱關係

✒︎ Publisher & Subscriber 流程

首先,在實作之前。我們先來了解 Combine 中 Publisher 以及 Subscriber 間的訂閱以及傳遞的流程,如下圖:

基本上就是 Subscriber 會訂閱(附加 or 連接)在一個 Publisher,而這時 Publisher 會返回一個 Subscription 也就是所謂的訂閱,我們會藉由這個訂閱來保持兩者間的訂閱關係,我們也可以藉由移除它或是主動調用 cancel() 來取消訂閱關係。一旦有了這個訂閱關係後,Subscriber 會向 Publisher 要求值,而 Publisher 會向 Subscriber 發送值以及發送完成或是錯誤。

✒︎ 實作應用介紹:

首先,我們來實作一個簡單的應用,一個單純把 TextFiled 中的 text 內容在其上方的 Label 中顯示:

在我們不用任何框架的情況,最單純的方式應該是透過 didSet 來實現:

接著讓我們看看如何使用 Combine 提供的內容來達成一樣的效果吧!

✒︎ 實作訂閱關係:

為了方便管理以及存儲的訂閱關係,首先我們在 ViewController 中宣告一個存儲訂閱的 Set ,其類型為 Set<AnyCancellable>

private var subscriptions: Set<AnyCancellable> = []

1. 標記 @Published:

首先,第一種方式是使用 @Published 這個 property wrapper 來標記這個 username 屬性,而之後我們透過 $ 符號來訪問其中的 Publisher

接著我們可以簡單的透過 sink 或是 assign 的方式來創建訂閱關係:

比較特別的是 assign(to:on:) 這個方式,透過這個方式我們可直接把值透過 keyPath 的方式分配物件的特定內容中,而不是類似於 sink 的閉包方式。如此一來也可以省略掉需要處理捕獲值 weak 或是 unowned 的狀況。

2. 透過 Subject 傳遞

接著我們換成以 Subject 方式來處理。首先我們使用 PassthroughSubject 來處理,而因為 Subject 也是一種 Publisher,所以我們一樣可以使用 sinkassign 的方式創建訂閱。接著使用 Subjectsend 方法來發布值:

接著我們使用另一個 Subject,叫做 CurrentValueSubject 。我們可以透過更改該 subject 中的 value 來發布值,或是一樣透過 send 方法來發布值。

在這兩個 Subject 中我們將其泛型定義為 <String?, Never> ,前面的表示傳遞的類型,而後面的是指錯誤的類型,在這邊因為我們不會有任何錯誤,所以可以使用 Never

3. 透過 NotificationCenter.Publisher

這邊我們也可以使用 NotificationCenterPublisher ,我們將它用於 UITextField.textDidChangeNotification 事件中,並且將 object 設置為 usernameTextField,接著我們透過幾個 operator 將 notification 轉換為 String?,並且一樣透過 assign 方法分配給 usernameLabeltext

透過這一連串的程式碼後,我們就創建完成 Publisher 以及 Subscriber,並且連接完成其訂閱關係了。

✒︎ 後記:

最近因為 Combine 的問世,強迫自己學習一些當前熱門的技術,而確實 Combine 的出現對於我編寫程式碼的概念也有了一個重大的改變,最近也一直不斷的在研讀 MVVM 相關的文章,希望自己之後能配合 Combine 寫出一個完美的架構。而有關於 Combine 更清楚或詳細的介紹,這邊推薦可以去看 WWDC 中介紹 Combine 的幾個片段,可以更了解他的流程以及強大。

--

--

Jeremy Xue
Jeremy Xue ‘s Blog

Hi, I’m Jeremy. [好想工作室 — iOS Developer]