Reputation: 794
I'm looking to create a Combine publisher/subscriber/subscription that behaves like this:
struct Change<Value> {
let new: Value
let previous: Value?
}
let pub = PassthroughSubject<Int, Never>()
let cancellable = pub
.change()
.sink { (change: Change<Int>) -> Void in
print(change)
}
pub.send(1) // prints Change(new: 1, previous: nil)
pub.send(2) // prints Change(new: 2, previous: 1)
pub.send(3) // prints Change(new: 3, previous: 2)
Having trouble coming up with the right implementation. I've made my own Publisher/Subscription to wrap external API calls and the sort, but can't come up with the right combination when some state needs to be retained, like the previous value in this example (I think this means you need a custom Subscriber?)
An alternate syntax with the same semantics would also be acceptable, if for some reason the .change()
syntax is unworkable.
Upvotes: 2
Views: 865
Reputation: 385650
You can build the change
operator out of the scan
and map
operators like this:
struct Change<Value> {
var old: Value?
var new: Value
}
extension Publisher {
func change() -> Publishers.Map<Publishers.Scan<Self, (Optional<Self.Output>, Optional<Self.Output>)>, Change<Self.Output>> {
return self
.scan((Output?.none, Output?.none)) { (state, new) in
(state.1, .some(new))
}
.map { (old, new) in
Change(old: old, new: new!)
}
}
}
Demo:
let pub = PassthroughSubject<Int, Never>()
let ticket = pub
.change()
.sink { print($0) }
pub.send(1)
// Output: Change<Int>(old: nil, new: 1)
pub.send(2)
// Output: Change<Int>(old: Optional(1), new: 2)
pub.send(3)
// Output: Change<Int>(old: Optional(2), new: 3)
Upvotes: 5