RxFlow Part 3: Tips and Tricks

Thibault Wittemberg
5 min readDec 22, 2017

--

RxFlow is a navigation framework for iOS applications, based on a Reactive Flow Coordinator pattern. This project is part of the RxSwiftCommunity Organization.

Its detailed conception is explained in these 3 articles:

Here is the Github Repo: https://github.com/RxSwiftCommunity/RxFlow

Thanks for you feedback, and feel free to contribute 🖖

Let’s dive into some tips and tricks I struggled with about Reactive Programming.

UIViewControllers made Reactive

As we saw in part 2, we needed, at some point, to know when a Presentable was displayed or not, in a Reactive way. A Presentable exposes 3 Observables:

In RxFlow, UIViewController conforms to this Protocol, therefore we must find a way to make them Reactive.

Hopefully a great project that have discovered along the way has helped a lot in doing this: RxViewController.

It gives a Reactive extension to UIViewControllers by applying the pattern I describe in this post: Verstatile name space in Swift. Moreover it uses RxCocoa built-in functions that allows to observe selector calls. Once I had understood the concept I made my own extension to UIViewController.

For the record, this is how It is used by the Coordinator, where “nextPresentable” is the Presentable that has been produced by a “navigate(to:)” function on a Flow. We only listen for the next Stepper after the very first display of the associated Presentable.

Let’s take a pause

Another key principle in RxFlow is: what happens in a Flow, stays in a Flow. Therefore, I had to find a way to “pause” the Steps’ subscriptions if the Flow was not on the top of the view hierarchy anymore.

RxSwift does not provide “out of the box” a way to pause a subscription, but RxSwiftExt does. This is a project from the RxSwiftCommunity. It adds a lot of new operators to RxSwift, such as “pausable”.

It pauses the elements of the source observable sequence unless the latest element from the second observable sequence is true.

Let’s take a look at the implementation.

In fact, this is just a combination of 3 RxSwift built-in operators:

  • withLatestFrom: which associates to the value triggered by the main Observable, the last value of another Observable called “pauser” (the one that drives the pause)
  • filter: which only accepts values from the “pauser” Observable that are true
  • map: which ignores the pauser Observable values so that only the value that is returned is the one from the main Observable

Again, this is how it is used by the Coordinator:

The is very straightforward to read: nextStepper’s Steps are paused when values from “rxVisible” Observable are false.

Protocols with stored properties ?

Being a Protocol Oriented framework, RxFlow wants the developer to implement several Protocols. When you build that kind of framework, you don’t want the user to struggle with too much functions or properties he would have to implement to fulfill those protocols.

Functions are not a problem, as you can provide default implementation with Protocol extensions. But properties are an issue, because Swift does not allow to store them in such an extension.

For instance, when you implement the Stepper Protocol, you are offered a “step” property that allows to trigger new Step values. How did I do this ?

Again the RxSwiftCommunity was of great help here. I was inspired by NSObject-Rx. This project proposes an extension to NSObject that stores a RxSwift DisposeBag. The aim is to provide a default DisposeBag to every class that extends NSObject, in particular UIViewControllers. It was precisely what I needed but in a protocol extension. Here is the code of Stepper.

All the magic happens in the “step” computed property. We use the “objc_setAssociatedObject” function to store a reference to a BehaviorSuject (see this NSHipster article). Each time this property is accessed, we retrieved this stored reference (at the first call, the BehaviorSubject is created and associated to the subjectContext reference).

There is a drawback to this trick. Protocols can be adopted by value types such as Structs which means memory is handled in the stack, not in the heap (like reference types). Therefore the lifecycle and reusability of a Struct instance are handled by the Swift runtime. When the runtime is going to reuse an instance it is not sure what happens to the “objc_getAssociatedObject” associated value. To make it safe, this kind of protocol should be constraint to be implemented by a class only, this will ensure that everything happens in the heap.

Give it back to community

As you can see, some key features in RxFlow are based on work done by the developers community. It is something you have to consider when you open source a project on your own: You will need help ! I think this is important to give it back to the community.

In RxFlow’s case, I had the opportunity to open 2 PRs that have been merged:

It felt really good to know that my code could help other developers.

Conclusion

It has been quite a challenge to make my first open source project available. This was NOT as easy as one can think because you have to:

  • gather and synthesize all the ideas that have led you to your project (ideas from former projects, problems and solutions you’ve encountered, …). So take it easy and think about it before coding anything :-)
  • try to pick the appropriate patterns according to the complexity of your project, do not over engineer your work
  • think as if you were the guy who will use your code, keep it as simple as possible (this is the hardest thing)
  • write a good README because the code is not enough to make your project attractive
  • be professional with your sources management. Nobody wants to contribute to a project that seems ugly (git CLI is your best friend)
  • try to write blog articles to share your work, you will get feedback from smart people
  • keep the faith, you will be discouraged from time to time. So give it a break if you are overwhelmed, do some brain washing, and ideas will come back later.

RxFlow is out in version 1.0.1 on CocoaPods and Cartage. I will now use it in my new side projects which I will be talking about in the next few posts !

RxFlow Github repo: https://github.com/RxSwiftCommunity/RxFlow

I hope you enjoyed this reading about Reactive Flow Coordinator. Feel free to contact me if you have questions or comments about RxFlow.

--

--

Thibault Wittemberg

My name is Thibault Wittemberg, I am a mobile architect in Montreal and I’m always looking for tips ‘n tricks to improve code awesomeness (twittemb.github.io).