Swift Combine ZIP

The Zip operator buffers values from each publisher until a complete set is available, then emits them in order. The key difference with latest is that combineLatest: Emits whenever any publisher changes, using most recent values“ wheras ZIP emits when all publishers provide new values. (it follows the sequence)

ZIP buffers values until matching pairs are available

CombineLatest - picks up the latest value from the upstream.

CombineLatest:

  • One buffer slot per publisher

  • Only keeps most recent value

  • Example: a.send(1), a.send(2) - only 2 is buffered -The buffering is done by the combineLatest

Zip:

  • Unlimited buffer per publisher

  • Keeps values in sequence

  • Example: a.send(1), a.send(2) - both 1 and 2 are buffered - The buffering is done by the ZIP

This is a reason Zip is good for sequential operations while CombineLatest is better for state/UI updates.

Here is a visual representation of how ZIP can be used for password validation

What do you think of it is?

It is a buggy implementation as a change in user name or password will require another change in the other publisher as well. A combineLatest is an appropriate candidate here.

Whats a good use case?

File Upload with Thumbnail

class Fileuploader {
    let fileData: AnyPublisher<Data, Error>
    let thumbnailData: AnyPublisher<Data, Error>
        private var cancellables = Set<AnyCancellable>()

    func uploadWithThumbNail() {
        Publishers.Zip(fileData, thumbnailData)
            .sink(receiveCompletion: { completion in
                switch completion {
                case .finished:
                    print("Both file and thumbnail uploaded")
                case .failure(let error):
                    print("Upload failed: \(error)")
                }
            }, receiveValue: { (file, thumbnail) in
                // Both are guaranteed to be ready together
                // One can't proceed without the other
                self.uploadToServer(file: file, thumbnail: thumbnail)
            })
            .store(in: &cancellables)
    }
}