Combine学习笔记
Combine
Combine是一个函数响应式编程库。
Publisher Operator Subscriber
Publisher(发布者)生成并发布数据。Publisher 是一个协议。
- 发布者可以发布0个1个或多个数据,然后正常结束或出错。
- 发布者的类型由所发布的数据(output,输出)的类型和所发生的错误(failure,失败)的类型构成。
<Output Type, Failure Type>
Operator(操作符)响应和更改数据。
- 操作符的输入类型由所接收的数据(input,输入)的类型和所接收的错误(failure,失败)的类型构成。
- 操作符的输出类型由所生成的数据(output,输出)的类型和所发生的错误(failure,失败)的类型构成。
<Input Type, Failure Type>
to<Output Type, Failure Type>
Subscriber(订阅者)订阅数据。Subscriber 是一个协议。
- 订阅者的类型由所接收的数据(input,输入)的类型和所接收的错误(failure,失败)的类型构成。
<Input Type, Failure Type>
// Publisher
Just(5)
// Operator
.map { value -> String in
return "a string"
}
// Subscriber
.sink { receivedValue in
print("The end result was \(receivedValue)")
}
Subject
Subject 是指遵循 Subject 协议的特殊发布者。Subject 协议继承自 Publisher 协议。
Subject 通过该协议中的 .send(_:)
方法来发布数据。
常用 Subject 有 CurrentValueSubject 和 PassthroughSubject。
- PassthroughSubject 没有初值,没有当前状态(值),订阅者无法接收订阅之前发布的数据。
PassthroughSubject 是门铃,没有开关状态,只有在家才能接收其信息。 - CurrentValueSubject 有初值,有当前状态(值),订阅者可以接收订阅之前最后发布的数据。
CurrentValueSubject 是电灯,有开关状态,回家即可观察其状态。
PassthroughSubject vs. CurrentValueSubject explained
let relay = PassthroughSubject<String, Never>()
let subscription = relay.sink { value in
print("subscription1 received value: \(value)")
}
relay.send("Hello")
relay.send("World!")
/*
subscription1 received value: Hello
subscription1 received value: World!
*/
let variable = CurrentValueSubject<String, Never>("")
variable.send("Initial text")
let subscription2 = variable.sink { value in
print("subscription2 received value: \(value)")
}
variable.send("More text")
/*
subscription2 received value: Initial text
subscription2 received value: More text
*/
Subscriber Cancellable
常用订阅者有 sink 和 assign。
sink 使用回调函数来处理结果值。
assign 使用结果值来设置其他值。
assign(to:on:)
将结果值赋予其他某个对象的某个属性。
assign(to:)
将结果值赋予其他某个Publisher。
Cancellable (可取消)是一个协议。
sink 和 assign(to:on:)
返回 Cancellable 的实例。
通过调用 Cancellable 协议的 cancel 方法可以取消订阅。
let cancellable = publishingSource.sink { someValue in
print(".sink() received \(someValue)")
}
// cancellable.cancel()
let cancellable = publishingSource
.receive(on: RunLoop.main)
.assign(to: \.isEnabled, on: yourButton)
// cancellable.cancel()
publishingSource.assign(to: &publishingSource2)
AnyPublisher AnyCancellable
AnyPublisher 为遵循 Publisher 协议的具体类。
通过调用 Publisher 协议的 eraseToAnyPublisher 方法可以将任何 Publisher 对象转化为 AnyPublisher 对象,方便统一处理并隐藏真实类型。
AnyCancellable 为遵循 Cancellable 协议的具体类。
sink 和 assign(to:on:)
返回 AnyCancellable 的实例。
AnyCancellable 的实例必须保存在该类型的变量或容器中。否则该实例会被回收并导致订阅被取消。
let pub: AnyPublisher<String, Never> = ["Here","we","go!"].publisher
.eraseToAnyPublisher()
var subscriptions = Set<AnyCancellable>()
pub.sink { receivedValue in
print("received value: \(receivedValue)")
}.store(in: &subscriptions)
/*
received value: Here
received value: we
received value: go!
*/
@Published
@Published 是一种提供 Publisher 的属性包装器(Property Wrapper)。
如果 v 是一个 Value 类型的属性,并且 v 属性使用 @Published 修饰,
那么 $v 就是一个 Published<Value>.Publisher
类型的 Publisher。
class Weather {
@Published var temperature: Double
init(temperature: Double) {
self.temperature = temperature
}
}
// temperature 的类型为 Double
// $temperature 的类型为 Published<Double>.Publisher
let weather = Weather(temperature: 20)
let cancellable = weather.$temperature.sink() {
print ("Temperature now: \($0)")
}
weather.temperature = 25
// Temperature now: 20.0
// Temperature now: 25.0