While working on an app where I needed to subscribe to multiple Combine publishers, I got confused about if I should use merge, zip or combineLatest. These publishers are quite similar with subtle differences. For making sure I never get confused about it, I am going to present examples in this week’s blog post.
Merge
Merge publisher just re-publishes any values received from any of the publisher. Useful when there are multiple sources of data we would like to combine into a single flow of updates.
@Published var state1 = "0" | |
@Published var state2 = "a" | |
func mergeExample() { | |
$state1.merge(with: $state2) | |
.sink { value in | |
print("sink", value) | |
} | |
.store(in: &cancellables) | |
print("will change state1 to 1") | |
state1 = "1" | |
print("will change state1 to 2") | |
state1 = "2" | |
print("will change state2 to b") | |
state2 = "b" | |
print("will change state1 to 3") | |
state1 = "3" | |
print("will change state2 to c") | |
state2 = "c" | |
} | |
/* output: | |
sink: 0 | |
sink: a | |
will change state1 to 1 | |
sink: 1 | |
will change state1 to | |
sink: 2 | |
will change state2 to b | |
sink: b | |
will change state1 to 3 | |
sink: 3 | |
will change state2 to c | |
sink: c | |
*/ |
Zip
Zip waits until it has received at least one element from each of the underlying publisher, and then delivers the value as a tuple. If one of the publisher publishes multiple values, then the first received value is part of the tuple and other values are part of next tuples after that.
@Published var state1 = "0" | |
@Published var state2 = "a" | |
func zipExample() { | |
$state1.zip($state2) | |
.sink { value in | |
print("zip", value) | |
} | |
.store(in: &cancellables) | |
print("will change state1 to 1") | |
state1 = "1" | |
print("will change state1 to 2") | |
state1 = "2" | |
print("will change state2 to b") | |
state2 = "b" | |
print("will change state1 to 3") | |
state1 = "3" | |
print("will change state2 to c") | |
state2 = "c" | |
} | |
/* output | |
sink ("0", "a") | |
will change state1 to 1 | |
will change state1 to 2 | |
will change state2 to b | |
sink ("1", "b") | |
will change state1 to 3 | |
will change state2 to c | |
sink ("2", "c") | |
*/ |
CombineLatest
CombineLatest publishes a tuple whenever any of the underlying publishers emits an element. The tuple contains the latest value from each of the publisher.
@Published var state1 = "0" | |
@Published var state2 = "a" | |
func combineLatestExample() { | |
$state1.combineLatest($state2) | |
.sink { value in | |
print("sink", value) | |
} | |
.store(in: &cancellables) | |
print("will change state1 to 1") | |
state1 = "1" | |
print("will change state1 to 2") | |
state1 = "2" | |
print("will change state2 to b") | |
state2 = "b" | |
print("will change state1 to 3") | |
state1 = "3" | |
print("will change state2 to c") | |
state2 = "c" | |
} | |
/* example | |
sink ("0", "a") | |
will change state1 to 1 | |
sink ("1", "a") | |
will change state1 to 2 | |
sink ("2", "a") | |
will change state2 to b | |
sink ("2", "b") | |
will change state1 to 3 | |
sink ("3", "b") | |
will change state2 to c | |
sink ("3", "c") | |
*/ |
If this was helpful, please let me know on Mastodon@toomasvahter or Twitter @toomasvahter. Feel free to subscribe to RSS feed. Thank you for reading.