People often talk about reactive programming, and RxSwift in particular, as the ultimate way to describe application logic — event chaining, error handling, asynchrony. But don’t forget, RxSwift is also a tool in its own right, allowing you to add reactive extensions to anything.
RxSwift has a large and creative community. There are currently 55 repositories of varying sizes and purposes in RxSwiftCommunity ‘s github repository. Their roots are in reactive programming.
Next I’ll talk about the must-have dependencies in my Podfile.
RxKeyboard
We all love overlapping password fields with our keyboards, don’t we?
I don’t want to count the lines of code or describe NotificationCenter
how disgusted I am with using . Just look at how cool it is to express changes in keyboard height through the concept of sequence of events. Let me remind you that all Rx operators are provided here. You can use it here debounce
, or in Observable
combination with another, etc. Here is my favorite example of declarative code:
RxKeyboard.instance.isHidden
.drive(backgroundFadeView.rx.isHidden)
.disposed(by: disposeBag)
I can explain it, when the keyboard is hidden, I hide it backgroundFadeView
; when the keyboard is visible, I show it backgroundFadeView
. Although you can see it at a glance.
RxGesture
This situation is very common when UIButton
there is not enough. Let’s compare the syntax:
...
I can explain again, we only filter .ended
the gestures and calculate the translation. But even if you’re not familiar with the framework or RxSwift, this is obvious.
The problem with this old Cocoa pattern is that the code is spread out across all classes. To find out what’s going on with the view, you have to dig through the entire class and find the code that actually should be in one place. you need to:
- Write callback function;
- create
GestureRecognizer
; - configure it (set maximum number of touches
maximumNumberOfTouches
); - Add it to the view;
The first item is the scariest. The class will have a function passed to #selector()
. Is this a real function? No, this is a callback function with a name for no reason. This function must be anonymous (such as a closure) to restrict developers from calling it manually.
Util functions like setupGestureRecognizer
this also have the same problem, because the component’s setup code is placed here. These functions are not really functions. They do not express the behavior of the class. We just need to separate the code in some way “to improve its readability”. At the same time, the size of the class increases, the meaning becomes less clear, and the real business logic becomes complex and difficult to understand.
With RxGesture, all your code (creation, configuration, callbacks) is in one place. You can quickly view and modify them. There aren’t any pointless utility functions that are the result of a futile attempt to keep code separated.
RxDataSources
How about the most concise part of dealing with the most important thing in every iOS developer’s life ( UITableView
/ UICollectionView
)? Such an important problem requires a lot of code.
We have code spread throughout the class, and delegates, and completely useless numbersOfRowInSection
and numberOfSections
methods. Sections should be expressed using language tools, such as generic structures SectionModel <String, Int>
, which require a section name and an array of section elements. Now, the number of sections and cells can be inferred implicitly. The length of the array is always equal to the number of sections, and the length of the nested array is equal to the number of cells in the section.
And there is no need to IndexPath
access the items in the array. Keep it simple. The closure below configureCell
takes the model as a parameter. The programmer simply creates a cell from it.
There is an added bonus – the diff algorithm, which works in O(N) complexity. We will go into details in the next article. Just emit a new partial array and the framework will update only where needed. No more calls are needed reloadData
. Additionally, animation updates and convenient closures are supported out of the box instead of deprecated delegates. For me, using a footer activity indicator in a collectionView has never been more convenient.
RxSwiftExt
RxSwift implements the reactiveX.io specification but is not very open to new ideas. But this does not hinder the development of the community, hence the custom operator library . They’re all very small and simple, but they help me avoid writing dozens of lines of code every day.
If you already have experience using Rx, you may be interested in best error handling practices. Some would suggest using the Railway pattern and Result
type instead of onNext
the onError
indispensable callback system.
My favorite method is to split the sequence of events into a sequence of errors and a sequence of elements. With this approach, there is no chance that any observable will complete or fail with an error unless you want it to.
I recommend you read more about handling RxSwift errors with Materialize here .
RxFlow
A great framework for handling navigation problems in a passive way . An article about it will be published soon, if you don’t want to miss it, please follow me 🙂
It’s easy to see that reactive frameworks combine similar syntax and motivations. People want to reduce the amount of code without reducing readability. RxSwift uses asynchronous event working methods to really allow you to do this. You only need one line of code, whereas an imperative style might require ten lines of code.
I highly recommend browsing the other libraries in RxSwiftCommunity. You’ll find reactive extensions for many iOS widgets, as well as a variety of architectures including unidirectional data flow. It’s always useful to know other ways to solve everyday tasks. Maybe they’ll be better than yours?
If you like this story, please like and share it to help others find it! Feel free to leave a message below. Follow me to learn more about RxSwift.