Explained with example
In this article we will try to understand what a Combine pipeline looks like and how is it different from the traditional callback approach.
Ever since the Combine framework was introduced a few years ago by Apple starting iOS 13 many developers have adopted it their apps attracted by its ability to simplify complex processing steps in the form of so called pipelines.
We will work through a very simple set of examples (you can even run them in the Xcode playground !) where we try to accomplish the same task using the callback and the Combine approach.
We will try to implement a set of processing steps where we will fetch some employee data , apply a salary raise for the employees based on their department & finally generate a mailer that will print the final result of the processing.
We will implement this using the callback pattern and the Combine approach to visualise the difference.
Fetch Employees -> Apply salary raise -> Generate Mailer -> Print result
We will work with the below data structures that will represent the various data models that we are trying to work with and work towards.
We have the
EmployeeAddress & the
Mailer data structures
To keep things simple we will create a set of data in code that will help us to keep the implementation simple and focus more on the concepts (In practice the data will likely come from a remote ReST API etc).
Below is the data for an
EmployeeAddress data structure.
In the above example we have the
fetchEmployees implemented as a “callback” & Combine function.
In the first approach the called function receives a callback function as an argument that will be invoked with the set of employees. The second function uses a Combine built in convenience publisher
Justwhich helps to wrap any data and returns a Publisher.
eraseToAnyPublisher function helps to type erase the publisher output so that it is easy to process the output by clients and allows us to change the underlying implementation of the publisher output.
This publisher Never returns an error so the
<[Employee], Never> as the return type.
Apply Salary Raise
In the above functions, we loop through the
Employee array and apply a salary raise. We invoke the
callback or return a Publisher of type
AnyPublisher<[Employee], Never> as before.
As a final step of our processing we need to generate a
Mailer so that they can be sent to the next processing step (or just printed on the console in out case as we will see soon)
The above functions accept a set of
Employee and then either call the callback with a set of
Mailer objects or return a publisher.
We will now put the above individual implementations together to appreciate the difference !
As you can see, in the callback approach we need to nest the callbacks. You can imagine if the processing steps grow in the future the code will start to become complex to understand & maintain.
In the Combine approach, you can immediately see that the processing steps “chains “together to form a pipeline and is easy to reason and understand.
In the future if you were to ever need a new processing step (eg: Send email) you can easily introduce the step without having to necessarily increase the code complexity or needing a refactor.
flatMap is a Combine operator that transforms the elements from an upstream publisher into a new publisher.
sink is a built in subscriber that connects the publisher output to a closure (it usually ends a pipeline).
Note: It should be noted that to form a pipeline the output of the first publisher should match the input expected by the next publisher in the pipeline. So in our case
fetchEmployee returns a Publisher of type
AnyPublisher<[Employee], Never &
applyRaise expects an array or
The complete example can be found here.
For those wanting to understand the concepts, Combine docs from Apple are an excellent source of documentation. It is useful to grasp some key concepts such as
Subscriber to start, followed by built in publishers (such as
Empty among others) , subscribers such as
sink and last but not the least Combine operators (such as
collect among a huge list of others)