Skip to content

Instantly share code, notes, and snippets.

@jayrhynas
Last active November 4, 2020 15:56
Show Gist options
  • Save jayrhynas/f7572775aff01e78f64560cb6e88e3c6 to your computer and use it in GitHub Desktop.
Save jayrhynas/f7572775aff01e78f64560cb6e88e3c6 to your computer and use it in GitHub Desktop.
extension Publisher {
func combineLatestOnce<P>(_ other: P) -> AnyPublisher<(Output?, P.Output?), Failure> where P: Publisher, P.Failure == Failure {
return prepare()
.combineLatest(other.prepare())
.filter { $0.0 != nil || $0.1 != nil }
.eraseToAnyPublisher()
}
/// helper function for `combineLatestOnce`
/// immediately starts the stream with `nil` and follows each upstream value with `nil`
private func prepare() -> AnyPublisher<Output?, Failure> {
flatMap { value in
[value, nil].publisher
.setFailureType(to: Failure.self)
}
.prepend(nil)
.eraseToAnyPublisher()
}
}
let arrSub = PassthroughSubject<[Int], Never>()
let intSub = PassthroughSubject<Int, Never>()
let c = arrSub.combineLatestOnce(intSub)
.scan([]) { previous, newValues in
// new arrays get passed on, replacing the previous array
if let arr = newValues.0 {
return arr
}
// new integers get appended to previous array
else if let int = newValues.1 {
var arr = previous
arr.append(int)
return arr
}
// we shouldn't have both `nil` because of the `filter` in `combineLatestOnce`,
// but just in case, republish the previous array
else {
return previous
}
}
.sink {
print($0)
}
DispatchQueue.main.async {
// command output
arrSub.send([1, 2, 3]) // [1, 2, 3]
intSub.send(4) // [1, 2, 3, 4]
intSub.send(5) // [1, 2, 3, 4, 5]
arrSub.send([4, 5, 6]) // [4, 5, 6]
intSub.send(7) // [4, 5, 6, 7]
intSub.send(8) // [4, 5, 6, 7, 8]
}
RunLoop.main.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment