I need to build a Combine
pipeline using Swift
where 2 publishers are involved, pubA (A PassThroughSubject) generates values frequently and once pubB (another PassThroughSubject) generates a value, I need to use the latest value from pubA to trigger an event. The only strict condition is - the trigger should happen only on a new value of pubB (the driving publisher) and the pipeline should take most newest published value from pubA (should skip old values). Let me try to demonstrate with example:
pubA =>
1
2
3
4
5
pubB => true false true
Expected Output: (true, 3) (false, 5) (true, 5)
This seemed to be good for Zip
initially but zip pops old value not newest, i.e the output becomes (true, 1), (false, 2). And using combineLatest
triggers event whenever there is a value from any of the publishers & breaks the dependency to trigger only on pubB’s new value, so the output becomes (true, 3), (true, 4), (true, 5), (false, 5)
Appreciate any pointers.
Edit Notes:
Here is the final code that I came up with to match my exact requirement. I was reluctant to write a custom pub-sub or port combineLatestFrom
from RxSwift to Combine.
Thanks to @matt for directing me to the right approach he answered here: Swift Combine operator with same functionality like `withLatestFrom` in the RxSwift Framework
import Combine
import Foundation
let pub1 = PassthroughSubject<Int, Never>()
let pub2 = PassthroughSubject<Bool, Never>()
var subscriptions = Set<AnyCancellable>()
pub2.map { value in (unique: UUID(), value: value) }
.combineLatest(pub1)
.removeDuplicates {
return $0.0.unique == $1.0.unique
}
.map { (tuple) in
return (tuple.0.1, tuple.1)
}
.sink { event in
print(event)
}
.store(in: &subscriptions)
pub1.send(1)
pub1.send(2)
pub1.send(2)
pub1.send(3)
pub2.send(true)
pub1.send(4)
pub1.send(5)
pub2.send(false)
pub2.send(true)
And the output is:
(true, 3)
(false, 5)
(true, 5)