Advertisement

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
    }

该平台的主要职责包括两个方面:一是向订阅者推送新的事件及其相关数据;二是为订阅者做好充分准备。此外,在输出端设置了相应的参数配置项以支持订阅功能的实现。在输出参数中包含了两种基本类型:一种是与当前时间相关的最新事件;另一种是与之前时间段相关的延迟事件;第三种则是由于网络连接中断导致的数据丢失。

  1. 输出类型字段中的新增值:表明事件流系统接收到了新的数据记录。
  2. 错误配置字段中的异常状态:表明系统检测到故障并终止了数据流程。
  3. 完成标记字段中的状态更新:意味着所有数据元素已成功提交至目标系统,并标志着整个事件处理流程结束。

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>)
    }

在定义中,InputFailure 分别代表了可接收的事件流数据类型和错误类型。为了订阅某个 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接收处理。

写在最后

发布方、操作方和订阅方共同构建了一个完整的链条。当建立了事件流的响应链时,在应用中伴随状态的变化发生着;这些都是响应式编程处理异步程序的核心组件。

全部评论 (0)

还没有任何评论哟~