2021-01-29

Combine之Subjects

在响应式编程的世界中,Subject不太好翻译。在Combine中,存在两个Subjects,本质上,他们就是一种特殊的publisher。之所以称他们是特殊的,是因为他们不仅包含publisher通用的一些特性,还具有独特的地方,接下来,我们逐个解释。

先看看Subject的定义:

/// A publisher that exposes a method for outside callers to publish elements.
///
/// A subject is a publisher that you can use to ”inject” values into a stream, by calling its ``Subject/send(_:)`` method. This can be useful for adapting existing imperative code to the Combine model.
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public protocol Subject : AnyObject, Publisher {

    /// Sends a value to the subscriber.
    ///
    /// - Parameter value: The value to send.
    func send(_ value: Self.Output)

    /// Sends a completion signal to the subscriber.
    ///
    /// - Parameter completion: A `Completion` instance which indicates whether publishing has finished normally or failed with an error.
    func send(completion: Subscribers.Completion)

    /// Sends a subscription to the subscriber.
    ///
    /// This call provides the ``Subject`` an opportunity to establish demand for any new upstream subscriptions.
    ///
    /// - Parameter subscription: The subscription instance through which the subscriber can request elements.
    func send(subscription: Subscription)
}
复制代码

通过上边的代码可以看出,Subject本身就是一个协议,因为它继承了Publisher协议,所以才说它是一种特殊的Publisher。它最核心的内容是提供了3个send方法:

  • func send(_ value: Self.Output)该方法可以让我们在任何时候任何地方发送任何数据,这提供了非常灵活的数据发送能力。
  • func send(completion: Subscribers.Completion)该方法可以让我们发送.finished或者.failure事件,用于结束该pipline。
  • func send(subscription: Subscription)该方法发送一个subscription给订阅者,建议两者沟通的一个中间渠道。

总之一句话,sendSubject的核心方法,也是核心理念。

CurrentValueSubject

[图片上传中...(image-78de00-1611882474037-2)]

CurrentValueSubject最特殊的地方有2点:

  • 它有一个初始值,也可以称之为最开始它当前的值就是它的初始值
  • 当调用send发送新的数据的时候,它更新当前的值,然后发送给订阅者

其中,最有意思的一点是,当它再次收到一个新的订阅的情况下,它会给新的订阅着发送它当前的值:

[图片上传中...(image-77b814-1611882474037-1)]

总之一句话,CurrentValueSubject是有记忆的。

let publisher = CurrentValueSubject(5)

cancellable1 = publisher
    .sink(receiveValue: { print($0) })

publisher.send(1)
publisher.send(2)
publisher.send(3)

cancellable2 = publisher
    .sink(receiveValue: { print($0) })
复制代码

PassthroughSubject

[图片上传中...(image-11d8-1611882474037-0)]

如果大家理解了上边讲解的CurrentValueSubject,那么就很好理解PassthroughSuject了,它更加简单直接,它不记忆任何状态,只传递数据。

这里要说的一点是,PassthroughSubject是一个比较常用的publisher,尤其用于test,主要原因是,它能够让我们自由控制数据的发送时机。

你可能感兴趣的:(2021-01-29)