Swift一個小例子帶你瞭解Combine中多重訂閱不丟失(auto replay)的方法

引子

Combine中雖然有衆多內置Operators,但是要想實現對同一個Publisher多次訂閱,且結果不丟失還是比較棘手的,除非實現自定義Publisher,但這不是今天我們的話題 😉

在這裏插入圖片描述

什麼是多重訂閱?

多重訂閱就是多個訂閱者訂閱同一個Publisher。

什麼是多重訂閱不丟失?

不丟失指的是,在有多個訂閱者的情況下,無論發生何種情況都可確保每個訂閱者都可以接收到每一個消息。

即這是一個自動重發的機制,因爲正常情況下Publisher源只會發佈一次消息,絕不會爲某個訂閱者再發一次,你錯過了只有怪你自己哦。

舉個栗子

拿從網絡讀取Web數據這個異步操作來說,如果有訂閱者在數據返回之後再訂閱,它顯然無法接收到之前發送的數據:

第一步: 創建發佈者

第二步: 訂閱者1訂閱

第三步: 發佈者返回Web數據

第四步: 訂閱者2接收到數據

第五步: 訂閱者2訂閱(接收不到之前的數據)

如上所示,除非使用某種緩存再重發機制,訂閱者2就會丟失之前的那次數據。

let url = URL(string: "https://www.csdn.net")!

let p = URLSession.shared.dataTaskPublisher(for: url)
    .share()
    .map(\.data)

	var subscriptions = [AnyCancellable]()

	// 模擬延時一段時間後再訂閱
	DispatchQueue.main.asyncAfter(deadline: .now()+5.0){
	    p.sink(receiveValue: {
	    	// 訂閱者2不會收到數據
	        print("2: \($0)")
	    }).store(in: &subscriptions)
	}
	
	// 訂閱者1立即訂閱
	p.sink(receiveValue: {
		// 訂閱者1可以收到數據
	    print("1: \($0)")
	}).store(in: &subscriptions)

上面這段簡單的代碼演示了多重訂閱丟失的問題.

那麼如何較簡單的解決上述問題呢?

在這裏插入圖片描述

多播前來拯救

Combine中有一個multicast(多播)操作符,用它可以較好地滿足上面的問題。

multicast操作符有一個重要的特性,按需手動刷新消息槽.

我們可以在需要時主動爲所有訂閱者發送消息,而不是讓發佈者“爲所欲爲”任性發送…

在這裏插入圖片描述

廢話打住,上代碼:

爲創建的發佈者鏈接multicast操作符:

let p = URLSession.shared.dataTaskPublisher(for: url)
    .share()
    .map(\.data)
    .multicast {PassthroughSubject<Data,URLError>()}

注意其返回另一個Publisher,其中的泛型類型不能錯!

現在運行代碼,是神馬結果???

結果就是不會有任何訂閱者收到數據,上面說了multicast之後必須由你手動刷新消息槽。

接着在創建訂閱者2的結尾加上一句:

// 手動刷新消息槽
p.connect()
    .store(in: &subscriptions)

再次運行代碼,你會發現兩個訂閱者都收到的消息,我們的目標就達到了 😉

總結

Combine中的操作符有很多,要想Combine用的好,用的妙,操作符必須爛熟於胸啊…

再會啦 😉

在這裏插入圖片描述

發佈了906 篇原創文章 · 獲贊 220 · 訪問量 223萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章