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 ("(\($0.previous), \($0.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) { ($0?.1, $1) }
.compactMap { $0 }
.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 ("(\($0.previous), \($0.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)) { ($0.1, $1) }.eraseToAnyPublisher()
}
}
3条答案
按热度按时间k5ifujac1#
这些是我提出的自定义运算符(称为
withPrevious
)。有两个重载,一个重载的初始前一个值是nil
,另一个重载提供初始前一个值,这样就不必处理可选值。存在第三个重载,其中
Output
本身是可选的,这导致previous
是Output??
类型的双可选(@richy在评论中指出的场景)。第三个重载将输出展平,以便previous
和current
都是可选的((previous: Output?, current: Output?)
与(previous: Output??, current: Output?)
相对)。区别是微妙的(超出了泛型约束),所以我特别指出:
Optional<(Output, Output)>.none
与Optional<(Output?, Output)>.none
。jvidinwx2#
我对
ReactiveSwift/ReactiveCocoa
并不完全熟悉,但根据您的描述,您可以使用.scan
,这似乎是一个比combinePrevious
更通用的函数。它接受一个初始结果(你可以把它做成一个元组),一个包含存储值和当前值的闭包,并返回一个新的存储值--在你的例子中,一个包含
(previous, current)
的元组:j8ag8udp3#
Cocoacasts有一个很好的例子:
https://cocoacasts.com/combine-essentials-combining-publishers-with-combine-zip-operator
zip操作符可用于创建发布者,该发布者发出前一个元素和当前元素。我们将同一个发布者传递给Publishers.Zip结构的初始化器两次,但对第二个发布者应用dropFirst运算符。这仅仅意味着第二个发布者不会发出原始发布者的第一个元素。
使用方法: