使用 Combine 合并先前的值

Combine previous value using Combine

如何使用 Combine 框架重写 ReactiveSwift/ReactiveCocoa 代码?我附上了截图 combinePrevious 文档中的意思。

let producer = SignalProducer<Int, Never>([1, 2, 3]).combinePrevious(0)
producer.startWithValues { value in
    print(value) // print: (0, 1), (1, 2), (2, 3)
}

我对ReactiveSwift/ReactiveCocoa不是很熟悉,但是根据你的描述,你可以使用.scan,这似乎是一个比combinePrevious更通用的功能。

它需要一个初始结果——你可以把它变成一个元组——、一个包含存储值和当前值的闭包,以及 returns 一个新的存储值——在你的例子中,一个元组(previous, current):

let producer = [1,2,3].publisher
                      .scan((0,0)) { ([=10=].1, ) }

producer.sink { 
   print([=10=]) 
}

这些是我想出的自定义运算符(称为 withPrevious)。有两个重载,一个是前一个初始值为 nil,另一个是您提供前一个初始值,这样您就不必处理可选值。

extension Publisher {

    /// Includes the current element as well as the previous element from the upstream publisher in a tuple where the previous element is optional.
    /// The first time the upstream publisher emits an element, the previous element will be `nil`.
    ///
    ///     let range = (1...5)
    ///     cancellable = range.publisher
    ///         .withPrevious()
    ///         .sink { print ("(\([=10=].previous), \([=10=].current))", terminator: " ") }
    ///      // Prints: "(nil, 1) (Optional(1), 2) (Optional(2), 3) (Optional(3), 4) (Optional(4), 5) ".
    ///
    /// - Returns: A publisher of a tuple of the previous and current elements from the upstream publisher.
    func withPrevious() -> AnyPublisher<(previous: Output?, current: Output), Failure> {
        scan(Optional<(Output?, Output)>.none) { ([=10=]?.1, ) }
            .compactMap { [=10=] }
            .eraseToAnyPublisher()
    }

    /// Includes the current element as well as the previous element from the upstream publisher in a tuple where the previous element is not optional.
    /// The first time the upstream publisher emits an element, the previous element will be the `initialPreviousValue`.
    ///
    ///     let range = (1...5)
    ///     cancellable = range.publisher
    ///         .withPrevious(0)
    ///         .sink { print ("(\([=10=].previous), \([=10=].current))", terminator: " ") }
    ///      // Prints: "(0, 1) (1, 2) (2, 3) (3, 4) (4, 5) ".
    ///
    /// - Parameter initialPreviousValue: The initial value to use as the "previous" value when the upstream publisher emits for the first time.
    /// - Returns: A publisher of a tuple of the previous and current elements from the upstream publisher.
    func withPrevious(_ initialPreviousValue: Output) -> AnyPublisher<(previous: Output, current: Output), Failure> {
        scan((initialPreviousValue, initialPreviousValue)) { ([=10=].1, ) }.eraseToAnyPublisher()
    }
}