使用 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()
}
}
如何使用 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()
}
}