Introduction to Reactive Programming in Swift

Hi! In this article, I will basically explain what reactive programming means, what benefits it brings and how not to shoot yourself in the foot while using it. The article mainly corresponds to the beginners level. If you identify yourself as a reactive God, then you won’t make much use of it.

alt

So, what actually is reactive programming? If you ever tried to grasp the meaning of this phrase, you would find a lot of different and difficult definitions that don’t bring any clarity to the beginners. By the way, it happened to me at the dawn of my “reactive” road. Studying various approaches (e.g., functional or OOP) confused me even more and, eventually, all that informational chaos set in my head.

alt

The first definition I found was something like “reactive programming is the programming paradigm that operates streams of data and events on which your program reacts” and so forth. Still, it was not clear enough for me to comprehend it.

At one point I thought that I’m not ready for such a “complicated” definition and should postpone studying for a better time, e.g. when I’ll become an App Architect. However, suddenly the eureka moment came to me and I understood that I needed just a simple explanation. That is why my goal here is to put this matter in simple terms and persuade you that reactive programming is really cool in use and definitely brings a lot of advantages to your projects.

alt

So as direction is given, let’s move on. Wikipedia provides the next definition: reactive programming - the programming paradigm, oriented on data streams and dissemination of changes across the program. That’s obviously not the best for the start, yet let’s give it a chance. I will try to express this interpretation in a more common way.

Reactive programming is the programming, based on continual changes which usually lead to altering and binding objects. This way we get the chain of changes through the application. It is similar to the Observer design pattern (if you do not know it, check out for sure), where the object that provides changes is a notificator and the triggered objects turn into observers. Moreover, triggered ones can also notificate, which bring us to the conclusion that all objects are notificators and observers at the same time. Finally, it comes just to simple binding of objects or actions.

Now, let’s try to understand Wikipedia’s statement piece by piece!

  1. programming paradigm - this is an approach for building apps.
  2. orientation on data stream - the chain that we create through objects’ binding. Admittedly, here we imply only the path for data transfer, but not the exact process of data transferring. This case can be compared to a water movement, where it flows from one point to another and creates a water channel, which in turn composes a water stream. Likewise, data also goes via data channels and streams.
  3. dissemination of changes - dispersing data (sending notifications) across the program and from one object to another. That is actually water that flows between spots.

alt

Besides, reactive programming stream can exist in three following phases:

Next - a stream came to one of its possible states. In this situation, we receive a notification that our stream (in other words, our object) changed its status (its value).

Completed - a stream reached its end point. The work with this channel is finished and it will not inform us anymore.

Error - a stream does not work correctly and reports us about some fault. For instance, a variable was not initialized properly.

Now you could certainly say that it’s not as hard as it seemed before, I hope so. Over and above, it was just theoretical explanation. You would probably want to look at some practical points. Let’s try a simple reactive example. Some of you might have even tried it before, yet didn’t know it was a reactive approach. In addition, I want to remark that it’s not a pure, or, as to say, full reactive. This one represents just a simple part of it and gives a better opportunity to understand the process we are working with. So here it is…

class SomeController {  
    var arrayOfData {
        didSet {
            someTableView.reloadData()
        }
}
}

Now let’s describe what we got. We have an array of data with binded table view. You could observe reactivity with the didSet method. Supposing our array with data is substituted for another one, then our table view will be triggered for redrawing. Isn’t it the same thing we were talking about? A change in one object automatically leads to transformation of others. In our case, we mean table view.

Previously I told that this is not the pure reactive. The reason is pretty simple. If we remove an object from the array, it won’t lead to any effect. We could only alter the table view by changing the whole array. That indicates, our table view will not represent a real state of a data array, and overall binding logic is ruined.
But stop. How then can we use reactive in our iOS application?

alt

In general, there are four possible solutions for it:
reloading methods as willSet, set and previously discussed didSet. They’re quite easy in use, safe in coding, readable and apparently the best choice to start with. However, these methods do not cover all reactive needs. At some moment in time, you will need a more powerful solution.
using notifications. On the one hand, it covers more reactive area. On the other hand, UI binding is hard to work with. Besides, transferring data globally through the entire application has never seemed the best choice.

KVO - comprises absolutely everything we need for reactive and supposes relatively easy work with UI. Nevertheless, this solution is unsafe for coding. Regarding lots of bindings in one class, I would not recommend to use it in your applications, as your notification handling method will become enormously huge.

Using outside libraries - perhaps, the best of all methods. It ensures less code (even less, comparing to the standard approach). The coding becomes readable, flexible to changes. and safe or, in simple terms, with less amount of bugs. In spite of cool advantages, this method also has pain points. Though it does not apply to native libraries, there is no guarantee that they will be supported in future. As a consequence, I do not advise to use it in bug problems. But, to my mind, the risk is worth it...

alt

To speak frankly, we should not waste our time on studying the first three solutions. The last one is the most peculiar. Obviously, these libraries are not native and probably most of you don’t even know how they operate. Starting a new project without an in-depth knowledge of libraries would definitely lead to fiasco. Just imagine a monkey with a granate. So let’s figure out how they work, using RxSwift library as a role model.

Why did I choose exactly this one? Firstly, it is written for the Swift language, what makes it closer to my heart and more clear due to the powerful language mechanism. Secondly, confidence in support staff and stability are guaranteed as it was implemented by famous RX libraries builder. And last, but not least, RxSwift library is one of the most popular nowadays. So as a direction chosen, let’s proceed!

alt

Techmagic - Good&Co case study