Reactive Swift: upgrading to ReactiveCocoa 3.0


If the title doesn't sound familiar to you, ReactiveCocoa is an FRP* inspired framework, counting remarkable usage in the Cocoa world. It's not just trending because it's fancy to try reactive programming, but there are several companies out there using it in production. Now with Swift coming into the picture, it has been rewarded with a brand new version, 3.0. If you are interested in some clarification on ReactiveCocoa 3.0, I suggest to read the framework documentation and the changelog in advance. If you are interested in how I upgraded my iOS app from ReactiveCocoa 2.4 to 3.0, just read on.

Why?

Because I've been using ReactiveCocoa 2 with Objective-C for almost a year now and I'm very excited to see what its creators considered important to change in the concept, how they leverage the benefits of the Swift language and how it feels to use the new framework.

I'm interested in how reactive programming (or #howcanicallit) evolves, especially in the world of Cocoa.

Swift is at our doorstep. We will use it, eventually.

The examples are from a project..

..which is the iOS app of the brewfactory family. You can find the whole source of BrewMobile on GitHub. It's close to my heart, because I really like the taste of the IPAs these guys brew with their home brewing machine. I've already shared some experiences about how to go MVVM & reactive with Swift using ReactiveCocoa 2.4 back then, with the very same project. Now is the time to make it RAC3ified.

IPA comes handy on Friday meetings

See @kutpet testing the reactive IPA enthusiastically.

Going 3.0

I thought I would struggle for a day to make the project RAC 3 compatible, then it happened in two minutes. I've updated my Cartfile and shot an update. The project built & ran and worked like before. I was able to upgrade the whole project using RAC 2 and 3 at the same time, reducing the old parts step by step like a tutorial.

Network requests

I started with transforming the composition of my HTTP requests, that felt pretty smooth. NSURLSession's rac_dataWithRequest gives you a SignalProducer back which you can apply operators on, like map, filter, or add any side effects with on.

UI interactions

Next I wanted to turn my RACCommands into Actions and CocoaActions. At first sight, Action might seem identical to RACCommand, but it's useful for a lot more. To make it work with UIKit elements though, you have to add CocoaAction to the picture.

Let's see the above created network request inside an Action.

Now, how to trigger it by a button press for example? Check out the view model for the connected CocoaAction.

As you can see, it's possible to pass an input value with it. Although the input (and output) type has to be defined with the original Action.

The view controller with the UIButton binding:

That's it! You can press the button and start brewing. Of course, if your HTTP request failed, you should get notified about it:

The observeOn(UIScheduler()) is necessary, because unlike RACCommand, Actions are not bound to the main thread by default.

Observable properties

Instead of all the RACObserve and RAC macros, now you can make your properties a MutableProperty. With the <~ operator, you are able to bind a Signal, a SignalProducer, or another property to a given property.

The cool thing is, its value is mutable but you are still able to define it as a constant. Mutable properties' producers come handy when you would like to operate on the observed values.

Let me know if you found the good old and operator which I apparently didn't.

There are a lot of examples in the project, using MutableProperty, I even updated my model's states with it. There is only one catch, which is about observing UIKit elements, so read on.

UIKit extensions

They are not here yet, but it is possible to build upon the Objective-C bridging. RACSignal has a new method toSignalProducer() which subscribes to the given signal for every start().

It also means you are able to add side effects for example to the returned SignalProducer.

@ColinEberhardt made a collection of handful extensions from this consideration. Let's see how UITextField's text became a MutableProperty.

And that's it.

Note that catch is a reserved word in Swift 2, it will become flatMapError in the future.

Again, you can find the whole code of BrewMobile on GitHub and you can also compare it to the older version. Feel free to send PR-s and issues, or correct me here in a comment.

The hard parts

As someone coming from Objective-C and ReactiveCocoa 2, I have to admit it was not easy to upgrade my project. Given it is brand new, we are not full of examples out there. With this post, I tried to give you some. What I suggest is to read a lot of tests and search the issues. They are not just up to date, but the contributors always answer the questions with suggestions and clear explanation, very useful, many thanks!

You might have the natural feeling, that the framework is a bit raw now and there is also some confusion out there which might alter the framework later, after the community starts using and help shaping it. The point is to start somewhere, hope this project will help you.

Swift 1.2 or 2.0?

The project (and this post) is currently Swift 1.2 compatible, but check out my new article about using Swift 2.0 and ReactiveCocoa 4.0, if you're interested in that setup.

Conclusion/feelings

I think ReactiveCocoa is a well-designed, mature system, people are building up big software with it, like GitHub for Mac, SoundCloud, etc., which is amazing. Although for beginners it might be hard to understand, given its complexity. I also understand that the contributors have a lot to carry on their shoulders with the Objective-C codebase.

GitHub language statistics, ReactiveCocoa

That's why it is a different story today, to come up with ideas based on the similar inspiration, but starting from zero, with Swift.

People who already use ReactiveCocoa in Objective-C will have a safe option to upgrade to Swift with ReactiveCocoa 3. I will definitely keep my eyes open though, there are promising projects out there.

*About FRP, Rx and sensitive definitions

I'm just a user of this framework, so I'm actually not concerned about ReactiveCocoa not being an official reactive extension and not conforming to a definition it should, to call it FRP. From my point of view, it is operating with streams and it is using functional operators on streams, so it makes my life easier. Now with Swift and the new concepts (e.g. separate hot and cold observables) it's actually even closer to the Rx ports, with some differences. FRP or not, ReactiveCocoa's design had been influenced by great theories combined with all the great people's ideas who's working on it, admirable anyway.

Useful readings in the topic

Swift

Reactive

Reactive Swift

ReactiveCocoa & Swift

Show Comments