COMBINE — X — FILE

INTRODUCTION

Some stuff that blew my mind:

  • First the paradigm: Combine uses a functional react paradigm (FRP).
  • Second “time”: in imperative programming of course we take time into account, but in FRP we must take a step further. Time applies in sequence of events, how we react, transform and stream values over it. “Callback hell” keep us out of focus about “time”, in Combine pipelines time become so clear and important that you are going to see things in a different way.
  • Third: Output and Failure. We’ve got used to pass success and failure completion block, nesting them, sometimes ignoring errors. In Combine streams results are returned as a generic Output and Failure types and this is super convenient.
  • Fourth: fancy operators.

PRECONDITION

This article is not for newbies you must have a basic knowledge of FRP and Apple Combine framework.

SUBSCRIPTION FLOW

This is one of the most important part of using Combine. Understanding the subscription flow is a major key for mastering the concept of back pressure.
In Combine is the subscriber that controls the flow of data.
When a subscriber subscribes to a publisher it requests data based on a specific demand. The demand is sent though the pipeline.
This process il called backpressure.

Publisher-Subscriber dance
The back pressure

MARBLE DIAGRAMS

If you look on the internet about FRP you are probably going to see also some weird drawings, the so called marble diagrams.
Marble diagrams are really helpful in understanding what happen in a FRP pipeline through time.
There is a wonderful app RXMarbles that can be downloaded from the App Store and Google Play Store. While this application has been made for ReactiveX it has a lot in common with Combine and I strongly suggest you to download and play with it.
Marble diagrams use this kind of conventions:

Marble diagrams convention
  • Timeline: the time line where events occurs it must be read from left to right, represented by a sequence of dashes, a single “-“ can represent a time slot.
  • Emitted values: usually represented as their value
  • End of stream: represented with the character pipe “|”
  • Error: represented by the character “#” or “X”
  • Operator: a huge ASCII art box with written inside the operator type

HOT PUBLISHER OR COLD PUBLISHER?

Sometimes this behavior is also know as hot observable and cold observables.
What’s the difference? in a cold publisher model values are sent only once you attach a subscriber, basically they are “lazy” and you are in charge to pull the trigger.
On the contrary in a hot publisher model, publishers start to fire once they are created, that means that usually you must cache the result to make it available once the subscriber is attached.
Depending on the context you will find that sometimes it will be better to have a cold publisher instead of hot or viceversa.
In Combine the model applied is “cold” with the exceptions of promises and subjects. If you ever seen the Deferred word around a promise is used to transform them from hot to cold.
In a cold publisher situation there is no need to cache result because a value exists only when a subscriber request it and old values cannot be requested since the same set will be given again each time you attach a subscriber. This have important root on how the publisher graph is handled by combine.
You can read more about this concept from CocoaWithLove.
I do agree with the reference when they say that while cold publisher are useful when you program in a full react environment when you have to interface with imperative programming hot publishers suit better and that is where Subjects in Combine play a major role.

SUBSCRIPTION SHADOW GRAPH AND EXPERIMENTS

There is something in Combine that a at first glance is very strange.
Let’s say that I have a publisher that publishes a value each second, from 1 to 5, I attach a subscriber (A) to it and then after 2 seconds I attach another one (B).
Can you tell me what is going to happen?
Probably you will reply to that question that I will see the first two value on A and later values on A and B.
Or at least this is what I thought.
In the reality is not working like that, the default combine behaviour in most of Combine operator is a resubscribe mechanism.
What is really happening here is that when you add the B subscriber the publisher start working as there where two different publishers, even if there is an overlap in time the B subscriber will start to receive values from the first one.

Resubscribe mechanism
Sharing the publisher

FLATMAP

FlatMap at the beginning was really a sort of exoteric operator, I’ve read a ton of articles about it without really understand how it works.
On apple documentation we find something like this:

Metastream
flatMap in action
Cap the demand
switchToLatest() in action

DISPOSE BAG AND TRICKS

If you are working with asynchronous functions in Combine you will probably find yourself in a situation where you will build your beautiful pipeline, lauch it, and nothing happens.

  • create an instance variable that points to it.
  • create a dispose bag, that is a fancy name for a collection that keeps all your AnyCancellable. This is so used that at the end of the sink you can add a .store passing the directly the dispose bag.
Courtesy Matt Neuburg Understanding Combine
extension Publisher { 
func customPrint(_ prefix: String = “”, to: TextOutputStream? = nil, isEnabled: Bool = true) -> AnyPublisher<Self.Output, Self.Failure> {
if isEnabled {
return print(prefix, to: to).eraseToAnyPublisher()
}
return AnyPublisher(self)
}
}

CONCLUSIONS

I really hope that I helped you somehow in dealing with Combine. Combine is a super powerful technology and is really amazing what you can do with it.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store