Combine 框架,從0到1 —— 5.Combine 中的 Subjects
本文首發(fā)于 Ficow Shen's Blog,原文地址: Combine 框架,從0到1 —— 5.Combine 中的 Subjects。
內(nèi)容概覽
- 前言
- PassthroughSubject
- CurrentValueSubject
- Subject 作為訂閱者
- 常見用法
- 總結(jié)
前言
正所謂,工欲善其事,必先利其器。在開始使用 Combine 進(jìn)行響應(yīng)式編程之前,建議您先了解 Combine 為您提供的各種發(fā)布者(Publishers)、操作符(Operators)、訂閱者(Subscribers)。
Subject 是一類比較特殊的發(fā)布者,因?yàn)樗瑫r(shí)也是訂閱者。Combine 提供了兩類 Subject :PassthroughSubject 和 CurrentValueSubject。
如果您想了解更多 Publishers 的用法和注意事項(xiàng),可以閱讀:Combine 框架,從0到1 —— 5.Combine 提供的發(fā)布者(Publishers)
PassthroughSubject
PassthroughSubject 可以向下游訂閱者廣播發(fā)送元素。使用 PassthroughSubject 可以很好地適應(yīng)命令式編程場景。
如果沒有訂閱者,或者需求為0,PassthroughSubject 就會(huì)丟棄元素。
示例代碼:
final class SubjectsDemo {
private var cancellable: AnyCancellable?
private let passThroughtSubject = PassthroughSubject<Int, Never>()
func passThroughtSubjectDemo() {
cancellable = passThroughtSubject
.sink {
print(#function, $0)
}
passThroughtSubject.send(1)
passThroughtSubject.send(2)
passThroughtSubject.send(3)
}
}
輸出內(nèi)容:
passThroughtSubjectDemo() 1
passThroughtSubjectDemo() 2
passThroughtSubjectDemo() 3
CurrentValueSubject
CurrentValueSubject 包裝一個(gè)值,當(dāng)這個(gè)值發(fā)生改變時(shí),它會(huì)發(fā)布一個(gè)新的元素給下游訂閱者。
CurrentValueSubject 需要在初始化時(shí)提供一個(gè)默認(rèn)值,您可以通過 value 屬性訪問這個(gè)值。在調(diào)用 send(_:) 方法發(fā)送元素后,這個(gè)緩存值也會(huì)被更新。
示例代碼:
final class SubjectsDemo {
private var cancellable: AnyCancellable?
private let currentValueSubject = CurrentValueSubject<Int, Never>(1)
func currentValueSubjectDemo() {
cancellable = currentValueSubject
.sink { [unowned self] in
print(#function, $0)
print("Value of currentValueSubject:", self.currentValueSubject.value)
}
currentValueSubject.send(2)
currentValueSubject.send(3)
}
}
輸出內(nèi)容:
currentValueSubjectDemo() 1
Value of currentValueSubject: 1
currentValueSubjectDemo() 2
Value of currentValueSubject: 2
currentValueSubjectDemo() 3
Value of currentValueSubject: 3
Subject 作為訂閱者
示例代碼:
final class SubjectsDemo {
private var cancellable1: AnyCancellable?
private var cancellable2: AnyCancellable?
private let optionalCurrentValueSubject = CurrentValueSubject<Int?, Never>(nil)
private func subjectSubscriber() {
cancellable1 = optionalCurrentValueSubject
.sink {
print(#function, $0)
}
cancellable2 = [1, 2, 3].publisher
.subscribe(optionalCurrentValueSubject)
}
}
optionalCurrentValueSubject 可以作為一個(gè)訂閱者去訂閱序列發(fā)布者 [1, 2, 3].publisher 發(fā)送的元素。
輸出內(nèi)容:
subjectSubscriber() nil
subjectSubscriber() Optional(1)
subjectSubscriber() Optional(2)
subjectSubscriber() Optional(3)
常見用法
在使用 Subject 時(shí),我們往往不會(huì)將其暴露給調(diào)用方。這時(shí)候,可以使用 eraseToAnyPublisher 操作符來隱藏內(nèi)部的 Subject。
示例代碼:
struct Model {
let id: UUID
let name: String
}
final class ViewModel {
private let modelSubject = CurrentValueSubject<Model?, Never>(nil)
var modelPublisher: AnyPublisher<Model?, Never> {
return modelSubject.eraseToAnyPublisher()
}
func updateName(_ name: String) {
modelSubject.send(.init(id: UUID(), name: name))
}
}
外部調(diào)用者無法直接操控 ViewModel 內(nèi)部的 Subject,這樣可以讓 ViewModel 更好地面對(duì)將來可能的改動(dòng)。
外部調(diào)用者只需要知道 modelPublisher 是 AnyPublisher<Model?, Never> 類型的發(fā)布者即可,無論內(nèi)部采用了 CurrentValueSubject 還是 PassthroughSubject 甚至是其他的發(fā)布者。
總結(jié)
相比于其他的發(fā)布者來說, Subject 是比較容易理解的,而且也是最常用到的。
只可惜,對(duì)比 Rx 提供的 Subject,Combine 中的 Subject 無法設(shè)置緩沖的大小。也許某天蘋果會(huì)對(duì)此做出調(diào)整吧~
推薦繼續(xù)閱讀:Combine 框架,從0到1 —— 5.Combine 常用操作符

浙公網(wǎng)安備 33010602011771號(hào)