I recently read Chris Adamson’s post, RxNot. I’ve been using RxSwift for a bit over a year now and I can say, unequivocally that it has made our app easier and more enjoyable to develop and that everyone should explore using a tool like RxSwift (though not necessarily RxSwift, I’ll get to that later).
Chris begins by listing the traditional methods of handling asynchronous communication from the days before blocks were introduced: Target-Action, KVO, Delegation, Notifications. With the exception of KVO (which nobody should ever use under any circumstances), these patterns still have their place. As excited as we are about the power of RxSwift, we still use Target-Action and Delegation everywhere in our app and we have absolutely not replaced them with Reactive programming. This was intentional. Target-Action is a well-understood pattern, it integrates seamlessly with Storyboards, anyone who’s been programming for iOS for longer than a week understands how it works. Delegation is even more prevalent in our app and it was even more important to us to keep Delegation vanilla. If you’re trying to debug a wonky UITableView, go look at the UITableViewDataSourcemethods in the associated view controller. There’s a time and place for trying to get clever, table view data source and delegate methods are not it.
Chris then discusses blocks and how a framework like Rx can make dealing with blocks smell a bit better, but that, in his opinion, it’s not worth the trade-off in complexity. Here’s where I strongly disagree with him. Actually, I’m not all that sure that I disagree with Chris, but I certainly disagree with how his former employer was using RxSwift.
There are a few keys to successfully integrating RxSwift into your project. First, don’t use any of the UI methods. Don’t hook Rx up to your buttons and table views. That shit is already a solved problem, just use Target-Actionand Delegation. It may be a bit more verbose than we would all like, but it’s trivial to understand and debug.
There are also challenging concepts beyond the operators that you’ll have to master, such as understanding the difference between “hot” and “cold” observables, and Rx-ifying your unit tests, which often requires wrangling the main-thread scheduler that emits events (or, worse, needing to explicitly take an ImmediateSchedulerType parameter in your code, so that you can get it to work with a test scheduler).
Second key to integrating RxSwift: don’t do any of the other things Chris is describing here. You don’t need to learn the difference between “hot” and “cold” if your observables are always cold. You don’t need to worry about testing threads and schedulers if your RxSwift code is just dumb wrappers around well-tested methods.
We exclusively use RxSwift for our asynchronous code. So much of our logic would be a nightmarish mishmash of asynchronous blocks and callbacks, but with RxSwift, it’s a neat, clean chain of strongly-typed functions. Each step is synchronous, easy to test and easy to reason about. We use Rx as the glue that binds everything together, and we couldn’t be happier.