Three Combine operators run publishers in parallel and gather the results, and the choice
between them is about timing: Zip waits for all, CombineLatest re-emits on any change,
Merge interleaves same-typed streams.
Zip: Wait for Every Publisher
Zip emits a tuple only when each publisher has produced a value, right for loading two
requests that must land together, like product details plus related products.
cancellable = Publishers.Zip(
service.fetch(product),
service.fetchRelatedProducts(for: product)
)
.sink(
receiveCompletion: { print($0) },
receiveValue: { [weak self] product, related in
self?.product = product
self?.related = related
}
)
CombineLatest: React to Any Change
Zip pairs values one to one, so it stalls when one input changes more often. CombineLatest
emits the latest values whenever any input changes, once each has emitted at least once.
That makes it the form-validation operator.
var isValid: AnyPublisher<Bool, Never> {
Publishers
.CombineLatest3($email, $password1, $password2)
.allSatisfy { email, password1, password2 in
email.contains("@") &&
password1.count > 7 &&
password1 == password2
}
.eraseToAnyPublisher()
}
Merge: One Pipe, Same Output Type
Merge and MergeMany interleave publishers of the same output type into one stream. The
classic use is cache then network: the cached list renders first and the fresh response
replaces it through the same assignment.
Publishers.MergeMany(
service.fetchCachedFavorites(),
service.fetchFavorites()
)
.replaceError(with: [])
.assign(to: &$products)