Visualize Combine Magic with SwiftUI — Part 4

Kevin Cheng
3 min readOct 31, 2019

What are the differences between Zip and CombineLatest

In the previous chapter, we successfully built a playground that accommodates operators like merge and append who take a list of Publishers and produce new one with the same type. Today, we want to crank it up a notch. We want to visualize operators that produce a tuple of all types of the Publishers. Both zip and combineLatest share this kind of behavior. Given 2 Publishers of String type, they will produce a new Publisher of<(String,String)>. In the end of this chapter, we will be able to tell the differences between zip and combineLatest by simply looking at the playground.

Add a wrapper around CircularView

In order to visualize tuples of values that are emitted from the operators, we concatenate CircularTextView to represent a tuple.

MultiCircularText is a wrapper of CircularTextView with an array of Strings.

@Binding var streamValues: [[String]]

TunnelView now holds 2-dimensional values.

ForEach(streamValues.reversed(), id: \.self) { texts in
MultiCircularTextView(texts: texts)
}

Everything stays the same except we use MultiCircularTextView and pass in this 2-dimensional texts.

struct TunnelView_Previews: PreviewProvider {static var previews: some View {
Section {
TunnelView(streamValues: .constant([["1"], ["2"], ["3"]]))
TunnelView(streamValues: .constant([["A"], ["B"], ["C"]]))
TunnelView(streamValues: .constant([["1", "A"], ["2", "B"], ["3", "C"]]))
}.previewLayout(.sizeThatFits)
}
}

Let’s preview quickly.

There you go. We can visualize tuple type now.

Upgrade single dimensional StreamView into 2-dimensional

@State private var stream1Values: [[String]] = []@State private var stream2Values: [[String]] = []@State private var streamResultValues: [[String]] = []var comparingPublisher: (AnyPublisher<String, Never>, AnyPublisher<String, Never>) -> (AnyPublisher<(String, String), Never>)

As you can see, all the stream values are 2-dimensional array now. Additionally, you can see the result of comparingPublisher closure is now a Publisher of Sting tuple.

Give it up to Zip and CombineLatest

Now we have prepared our playground. Let’s send Publishers operated by zip and combineLatest into DoublePublisherStreamView.

let publisher = self.invervalValuePublisher(array: ["1", "2", "3", "4"], interval: 1)let publisher2 = self.invervalValuePublisher(array: ["A", "B", "C", "D"], interval: 1.5)

Notice we delay publisher2’s value emission to make the result stand out between zip and combineLatest.

Here is the final result.

Because of the long width of the combined result, we display the playground in landscape.

Now you can easily tell that

Zip waits until both publishers emit values before it does while CombineLatest emits value whenever one of the sources does and combine its result with the latest values from other publishers.

Link to Source Code

Next chapter: Refine the playground

As we mentioned in chapter1, there are a few issues we found in this playground.

  1. The values in stream are sorted by the “String” value, not by emitted time.
  2. CircularView appears out of nowhere instead of appearing and moving from the entrance of the “tunnel” toward the front of the queue.
  3. In this chapter, we also notice that this tunnel only displays a limit amount of CircularView. When there are too many views in the tunnel, we want to move older views “out” toward the right side of the screen to keep space available for new views.

Since this is a series of both Combine and SwiftUI, in the next chapter, we will spend some time on SwiftUI components. Hopefully, all the streams will look better and more intuitive in terms of Combine’s visualization.

See next chapter, series Part 5 – SwiftUI ViewModifier, Animation, and Transition

There are certainly more I can learn than share. Please drop a line if you resonate or disagree with anything you see here.

--

--