Swift Combine — Publisher、Operator、Subscriber概念介绍
Combine框架介绍
Combine框架支持了基于声明式的Swift API,并提供了管理随着时间而变化的数据功能。该框架中的Combine声明发布者设计了一种机制,允许发布者宣布其随时间变化的内容,并通过订阅机制将这些变化传递给相应的接收方。
Combine框架为应用程序处理事件提供了一种声明式的处理方案。它允许为特定事件源构建单一处理链路,并避免潜在地实现多个委托回调或完成式处理闭包。当一个事件及其相关数据被发布时,订阅者将负责接收和利用这些信息,在此过程中这些事件和数据会经过一系列变形操作以满足最终需求。
在Combine系统中存在三种关键角色:其中一种是发布事件的完成者——Publisher;另一种是订阅事件的完成者——Subscriber;第三种则是处理事件转换与数据传输的角色——Operator。这些角色直接关联于这三种核心操作:发布、订阅以及数据转换与传输功能。
Publisher 发布者
作为事件发布机制的基础协议,“Publisher”标识izes事件发布者的角色。各类不同的...继承了该基础...协议。“Publisher”的定义相对简洁明了:涉及两个关联类型(...)以及一个接收机制。
public protocol Publisher<Output, Failure> {
/// The kind of values published by this publisher.
associatedtype Output
/// The kind of errors this publisher might publish.
///
/// Use `Never` if this `Publisher` does not publish errors.
associatedtype Failure : Error
/// Attaches the specified subscriber to this publisher.
///
/// Implementations of ``Publisher`` must implement this method.
///
/// The provided implementation of ``Publisher/subscribe(_:)-4u8kn``calls this method.
///
/// - Parameter subscriber: The subscriber to attach to this ``Publisher``, after which it can receive values.
func receive<S>(subscriber: S) where S : Subscriber, Self.Failure == S.Failure, Self.Output == S.Input
}
该平台的主要职责包括两个方面:一是向订阅者推送新的事件及其相关数据;二是为订阅者做好充分准备。此外,在输出端设置了相应的参数配置项以支持订阅功能的实现。在输出参数中包含了两种基本类型:一种是与当前时间相关的最新事件;另一种是与之前时间段相关的延迟事件;第三种则是由于网络连接中断导致的数据丢失。
- 输出类型字段中的新增值:表明事件流系统接收到了新的数据记录。
- 错误配置字段中的异常状态:表明系统检测到故障并终止了数据流程。
- 完成标记字段中的状态更新:意味着所有数据元素已成功提交至目标系统,并标志着整个事件处理流程结束。
Subscriber介绍
Subscriber 也是一个抽象的协议。
public protocol Subscriber<Input, Failure> : CustomCombineIdentifierConvertible {
/// The kind of values this subscriber receives.
associatedtype Input
/// The kind of errors this subscriber might receive.
///
/// Use `Never` if this `Subscriber` cannot receive errors.
associatedtype Failure : Error
/// Tells the subscriber that it has successfully subscribed to the publisher and may request items.
///
/// Use the received ``Subscription`` to request items from the publisher.
/// - Parameter subscription: A subscription that represents the connection between publisher and subscriber.
func receive(subscription: any Subscription)
/// Tells the subscriber that the publisher has produced an element.
///
/// - Parameter input: The published element.
/// - Returns: A `Subscribers.Demand` instance indicating how many more elements the subscriber expects to receive.
func receive(_ input: Self.Input) -> Subscribers.Demand
/// Tells the subscriber that the publisher has completed publishing, either normally or with an error.
///
/// - Parameter completion: A ``Subscribers/Completion`` case indicating whether publishing completed normally or with an error.
func receive(completion: Subscribers.Completion<Self.Failure>)
}
在定义中,Input 和 Failure 分别代表了可接收的事件流数据类型和错误类型。为了订阅某个 Publisher ,其 Subscriber 中的这两个类型必须满足其输出与错误类型的匹配。
Subscribers.Sink是一个简单的订阅者,在订阅时请求无限数量的值。
public func sink(receiveCompletion: @escaping ((Subscribers.Completion<Self.Failure>) -> Void), receiveValue: @escaping ((Self.Output) -> Void)) -> AnyCancellable
public func sink(receiveValue: @escaping ((Self.Output) -> Void)) -> AnyCancellable
既可以提供两种情况:一种是两个闭包;另一种是一个闭包。其中receiveCompletion用于接收 failure 或者 finished 事件;而 receiveValue 则用于接收 output值。
另一个常见的做法是采用assign函数。与通过sink提供闭包以执行任意操作不同,在使用assign时,请提供一个目标类及其指定属性名称。当实例化一个Assign实例时,请提供一个目标类及其指定属性名称。当输出事件触发时(即当输出事件到来时),其值将被赋值给指定属性。
public func assign<Root>(to keyPath: ReferenceWritableKeyPath<Root, Self.Output>, on object: Root) -> AnyCancellable
使用该方法需遵守特定条件,在SwiftUI框架中,默认情况下与View一一对应的ViewModel都继承了 ObservableObject这一特性。然而,并非所有继承该特性的对象都可直接赋值(assign)属性;只有当对象属于类(Class)时才能进行这种操作。
Operator介绍
该操作符提供了若干功能,在接收 upstream 产生的元素后会生成新的 downstream 发布器或订阅器。
通过将 Operator 串联起来构建一个发布机制,在这个机制中能够处理 upstream 发布器输出的所有内容。每个 Operator 都会创建并配置相应的 Publisher 或 Subscriber 实例,并将这些实例注册到调用该功能的 Publisher 上。
说起来不太好理解,看看下面这个例子。
let cancellable = [1, 2, 3, 4, 5].publisher
.filter {
$0 % 2 == 0
}
.sink {
print ("Even number: \($0)")
}
// Prints:
// Even number: 2
// Even number: 4
在示例中,一个数组Publisher发布了一系列整数1到5。filter操作符生成了一个新的Publisher来过滤这些数值中的偶数部分。随后使用的sink操作符则生成了一个对应的Subscriber角色,并将接收并处理每个数值作为其输入源。最后,“sink”所创建的Subscriber与之前通过filter生成的另一个Publisher之间建立了订阅关系,并且原始数组中的各个元素也会被该后续的Filtering Publisher接收处理。
写在最后
发布方、操作方和订阅方共同构建了一个完整的链条。当建立了事件流的响应链时,在应用中伴随状态的变化发生着;这些都是响应式编程处理异步程序的核心组件。
