Combine 学习笔记(三):Combine 的订阅流程与 Subscription

上一篇文章我们讨论了 Publisher 与 Subscriber 的基本概念以及使用方法。本文就以此为基础分析一下它们具体是如何发送与接收消息的,以及 Subscription 的作用。

一、订阅流程

Combine 的订阅流程可描述如下:

1. Subscriber 调用 Publisher 的 subscribe(_ subscriber: ) 方法开始订阅。
2. Publisher 调用 Subscriber 的 receive(subscription: ) 发送确认信息给 Subscriber。这个方法接收一个 Subscription。
3. Subscriber 调用 2 中创建的 Subscription 上的 request(_: Demand) 方法首次告诉 Publisher 需要的数据及其最大值。
4. Publisher 调用 Subscriber 的 receive(_ input: ) 发送不超过第 3 步 Demand 指定个数的数据给 Subscriber,并返回一个新的 Demand,告诉 Publisher 下次发送的最大数据量。
5. 执行 4 一直到 completion 事件发送。
6. Publisher 调用 Subscriber 的 receive(completion: ) 向 Subscriber 发送 completion 事件。这里的 completion 可以是正常 .finished,也可以是 .failure,如果是 .failure 会携带一个错误信息。需要特别注意的是,如果中途取消了订阅,Publisher 将不发送完成事件。

二、Subscription

注意到第二步调用 receive(subscription: ) 时凭空出现了 “Subscription”,实际上它充当了订阅过程中 Publisher 和 Subscriber 的协调者。在某种程度上可以说 Publisher 只负责发布数据,订阅流程的大部分工作是由 Subscriber 和 Subscription 完成的。Subscription 的定义如下:

public protocol Subscription: Cancellable, CustomCombineIdentifierConvertible {
    // 告诉Publisher可以发送多少数据到Subscriber
    func request(_ demand: Subscribers.Demand)
}

有了这个定义,我们就能站在 Subscription 的角度去描述 Combine 的订阅流程了:

1. Subscriber 调用 Publisher 的 subscribe(_ subscriber: ) 方法开始订阅。
2. Publisher 会调用 receive(subscriber: ),在该方法中创建 Subscription 对象并调用 Subscriber 的 receive(subscription: Subscription) 方法传递给 Subscriber。
3. Subscriber 调用 Subscription 的 request(_ demand: ) 方法首次告诉 Subscription 需要的数据及其最大值。
4. Subscription 调用 Subscriber 的 receive(_ input: ) 方法发送数据给 Subscriber,发送的数据量不超过 3 中 Demand 约定的最大值,并且返回一个新的 Subscribers.Demand,告诉 Subscription 下次需要的最大数据量。
5. 执行 4 一直到最后一个值发布完毕。
6. 当最后一次值发布完毕,Subscription 会调用一次 Subscriber 的 receive(completion: ) 结束订阅流程。

三、Back pressure

Combine 约定 Subscriber 控制数据流,用于解决 Publisher 发布数据过多过快的问题,要确保 Subscriber 收到的数据不会超过它请求的数据量。这个特性称之为 Back pressure(有些人翻译成 “背压”)。Subscription 中 request 方法的返回值 Subscribers.Demand 就是来告诉 Publisher 此次发布数据的最大值,且这个值是累加的。Subscribers.Demand 的常见取值有 .unlimited、.none 和 .max(Int)。之前讨论的 sink 在调用 Subscription 的 request 方法时,Back pressure 的值就是 .unlimited。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注