What is reactive programming?
“In computing, reactive programming is a declarative programming paradigm concerned with data streams and the propagation of change.” This is a definition of Reactive Programming provided by Wikipedia. And while this is the correct definition, it ain’t the easiest. For the concept that is pretty simple at its core. In imperative programming, if we state that variable A will be a sum of variables B and C, we will need to state that in the code every time we want it to be that value. In reactive programming that is not a case, because when thinking reactively the value A will be changed every time the variable B or C changes. So you can clearly see that this approach can be very helpful while writing mobile applications. How many times have you had a situation when you needed to control some slider or had a form to validate? Those are the places where the reactive approach shines, while you can observe all changes to the slider values in real time, or delay validation errors on input form for phone number or email. All that, and even more, you can easily and simply solve using reactive programming and the help of continuous streams. As the reactive programming enthusiasts say “Everything is a stream”.
Where do we use and want to use reactive programming in iOS App Development?
As it was said in the previous paragraph, the amount of places where reactive programming can have its plays is numerous, while there are two key actors in the reactive play. Native Apple’s Combine framework and third-party RxSwift. Their usage is very much similar and we can:
Create complete reactive networking layer with them
Do asynchronous validations on forms and inputs
Check sequences of output from IoT devices and filter or react on them
React on the applications states changes like screen rotations, logouts etc.
And much more…
It may be a little tricky, however, to notice its pros, as the whole actions mentioned above may be as well presented by the usage of the imperative approach.
And that is right, but the reactive approach just gives programmers a better ecosystem for programming in such highly dynamic and asynchronous environments that Mobile Applications are. But to convince you even more in the next paragraph I will present you the options, discuss their pros, cons and introduce you to the reactive programming world.
Making hands dirty with Reactive Programming in iOS
What are the options for iOS Developers?
Yeah now you know that reactive programming is great, thus what are the options for us iOS developers? Well there are two main frameworks for this concept: RxSwift and Combine.
Those two are very much alike but the thing that differs them from each other the most is that one is an OpenSource project and the second one is a native Apple framework.
RxSwift - old timer’s favorite
RxSwift is a part of the Rx frameworks family, originally started out by Rx.Net from Microsoft which evolved from proprietary Microsoft framework to open source libraries family. As it is said in the heading, it is an old timer’s favorite, while it is much older than Combine, and much more mature by that reason. The thing I’m talking about the most is that it is much bigger in helpers like custom schedulers (more on that topic later), full blown testing framework RxTest added which is extremely helpful, and RxCocoa which is basically a wrapper or helper for connecting UIKit components to RxSwift. And the thing that you need to consider when picking RxSwift is that it can be used on projects with target iOS version below 13, which I cannot say for the Combine.
RxSwift can be easily added to your project with Cocoa pods and configuration below ( there is SPM and Carthage version of this step too, but you are probably going to see this in most of the projects using RxSwift):
``` # Podfile use_frameworks! target 'YOUR_TARGET_NAME' do pod 'RxSwift', '6.5.0' pod 'RxCocoa', '6.5.0' end # RxTest and RxBlocking make the most sense in the context of unit/integration tests target 'YOUR_TESTING_TARGET' do pod 'RxBlocking', '6.5.0' pod 'RxTest', '6.5.0' end ```
And the you just need to run
``` pod install ```
Now you are ready to use RxSwift. For more in depth information about configuration you can visit the documentation of the project under given link: https://docs.rxswift.org/index.html
Additionally RxSwift is very nice to use if you are writing in other languages, while the streams and operations on those can be pretty much copy and pasted to other languages code bases and those are just going to work while the Reactive Foundation takes it very seriously for the implementation to be similar.
Combine - reactive for the future
Combine is a part of native libraries that we, as developers, get from Apple, with target project versions higher than 13 as I said before. This is its main downfall, while in a lot of projects we as developers will see RxSwift instead of Combine. That said, for the same reason it is very well integrated into the iOS development ecosystem. So when your project is fairly new you can add it with no problem and integrate with the codebase with no breeze, with no additional headspace for third party dependencies etc.
To use Combine you just need to type
``` Import Combine ```
On the top of your file, so the number of steps is very much shorter.
What are the reactive building blocks?
This article part will be mainly based on naming that is found in RxSwift while this one is more cross platform than the Combine, however, I will include the Combine naming if valid next to the RxSwift names.
Observable (aka Publisher)
As stated in RxSwift documentation: “It represents a push style sequence”, but what is that exactly? In short it is just a stream of some kind of values over time. Okey, that still is a little bit unspecific. An Observable (aka Stream) may emit any number of next(value) events, which is why it is called a push style sequence. But when the Observable will emit an error or completed event, the stream will be terminated and no new events will be emitted.
As you can see here we have an Observable implementation, with a stream of 4 numbers and when we want to get the values from it we can subscribe to it. That gives us four closures:
onNext – which returns latest event got from the stream
onError – which return error is occurred from the stream
onCompleted – which return when there was complete event
onDisposed – which return when the stream was disposed/erased from the memory
And there is one last part to the code, .disposed(by: disposeBag) and you can read about it in the next paragraph.
Dispose (aka Cancellable)
So basically, the DisposeBag, or Set of Cancellables in Combine, is an object that takes ownership of streams and takes all memory consumption into it. So when we subscribe on some stream and dispose of the stream to one of those objects, the owner being some class for instance will have an ownership on the memory of the disposeBag, and when it will be deinitialized the disposeBag will be deinitialized with it.
When I wrote about observers I didn’t mention that those are read only, and sometimes we want to mutate values or bind to events of such a stream. The type that gives us such ability is called an Observer. And in RxSwift or Combine there is an abstraction called a Subject that is both an Observer and Observable. I will write more about this topic in next parts of the series but for now all that you need to know is that there are some basic types of subject like:
PublishSubject (aka PassthroughSubject in Combine) – doesn’t replay elements to new subscribers
BehaviorSubject (aka CurrentValueSubject in Combine) – replays last element to new subscribers
ReplaySubject – replays any number of element to new subscribers
Operators give you an ability to manipulate the Observable streams, by their nature of combining and modifying operations they become a little “mathematical” under the hood. Most of them are chainable and cross-platform in other Rx implementations.
Debunking some reactive approach and streams myths
You don’t need to implement reactive streams everywhere
When starting out migrating or just implementing the reactive streams you do not need to use them everywhere, situations in which you have an old networking implementation and want to use some reactive streams are not uncommon. And you definitely can do that, step by step adding a little bit more complexity to the streams, and using their best parts.
It is not so hard
A lot of programmers I talk with say that reactive programming and the concepts of Rx or Combine are insanely hard. And yeah there is a little steep learning curve but the outcomes are pretty extraordinary. When you are going to learn a reactive approach, and it will click in your head, I bet you that it will be hard to come back to the imperative approach.
Okey but which one of those two frameworks?
Well the answer to that is not that simple while “it depends”.
Depending on your current UI framework usage or maybe knowledge of reactive programming in other languages that answer will change. But my opinion is that if you are concentrating mainly on native iOS development and want the most performante horse in the stable, with native integration to both of the Apples frameworks, meaning UIKit and SwiftUI (this one is the most preferred one), go with the Combine. It’s native, by some tests it is more performant then RxSwift and integrates extremely well with SwiftUI, and it’s the future of iOS development in my opinion. But if you have an old code base, and want to check this out, go with RxSwift, it’s a very mature third party framework, with a massive community and numerous online tutorials, courses or books. And if you are not a programmer, and just think about making a project in near future, I would highly recommend a reactive approach to the project, while it is the preferred way of writing mobile apps for me, and it will give them much better longevity if done right.
If you are curious about reactive programming and both of those frameworks, this is just a first part of the series about them, and the next article will be available shortly, so stick around for more.