Sunday, 26 February 2017

Migrating from ReactiveCocoa to ReactiveSwift

TL;DR - ReactiveSwift is the first version of ReactiveCocoa that fully embraces Swift 3. There are various API and functional changes introduced in this major release.

ReactiveSwift is a major release of what has until now been known as ReactiveCocoa, a popular reactive functional programming framework for iOS / OS X. The are two major changes introduced by ReactiveSwift: Firstly a full migration to Swift 3, including changing the API to match the new naming conventions. Secondly, UI bindings have been stripped out into a new framework, which is now called ReactiveCocoa.

Matching swift 3 API design

The most obvious change in ReactiveSwift is the new Swift-3-esque APIs. It's quite clear that they have worked hard to migrate all APIs to the new syntax. Below I list the most commonly used, however you can see all changes by looking at the deprecated list here.

Signal / SignalProducer

Old Method nameNew method name
observeNext:observeValues: / observeResult:1
startWithNext:startWithResult: / startWithValues
.throttle(<time>, onScheduler:)throttle(<TimeInterval>, on: ) 2


Old Method nameNew method name


Old Method nameNew method name
The method names for  mapfilter and flatMap have remained the same.


In ReactiveCocoa, it was possible to get a signal from notifications using the .rac_notifications property of the notification center. This has now been moved to the the reactive.notifications property.
Before ReactiveSwift:
    .startWithNext() {[weak self] notification in
        // do something with notification
In ReactiveSwift:
    .reactive.notifications(forName: MyNotificationName)
    .observe(on: UIScheduler())
    .observeValues{[weak self] _ in
        // do something.

Memory management of signals and signal producers

When disposing of a Signal before ReactiveSwift it was necessary to either send a terminating event, use one of the take:methods or dispose of the Signal's disposable. As the ReactiveCocoa 5 documentation puts it:
A signal created with Signal.init is kept alive until the generator closure releases the observer argument. 
This is no longer the case in ReactiveSwift, as the documentation states: 
[...] a Signal retains itself as long as there is still an active observer. In other words, if a Signal is neither publicly retained nor being observed, it would dispose of the signal resources silently.
This might be a subtle difference, but it does mean for example, that if a signal is no longer retained by the view controller, and nothing is observing it, then we can be sure that it will be disposed off automatically.
I would still prefer to make the memory management more explicit, for code clarity primarily. It's still possible (and recommended) to use the set of take methods to manager memory, as well as directly disposing the signal or sending a completed event to it. 
ReactiveSwift introduces a new type, Lifetime that can make memory management a little easier when working with multiple Signals or SignalProducers. When dealing with signals, it's important to think about how long should the observation of events last. For example, if we're observing a signal to update a UI component, say a UILabel, it makes sense to stop that observation if the label is no longer on screen. A Lifetime is simply an object that can be used to notify a Signal or SignalProducer we no longer want to observe their events. We can set up a Lifetime easily like this:
private let token = Lifetime.Token()
        public var lifetime: Lifetime {
            return Lifetime(token)
We can then use the take(during:) function to let the signal know that the object being deallocated will no longer be observing it:
    .reactive.notifications(forName: MyNotificationName)
    .observe(on: UIScheduler())
    .take(during: lifetime)
    .observeValues{[weak self] _ in
        // do something.
For Lifetime to work properly, we need to keep a strong reference to its token. It's crucial that only one strong reference ever exists for the token. When the object that holds the reference to the token (say a view controller) is deallocated, so will the lifetime, and the signal will know that this particular observation is complete.

ReactiveCocoa UI extensions

One of the major changes in ReactiveSwift is that all the UI extensions have been removed and a new framework called ReactiveCocoa (the name is of course confusing, as the whole project used to be called that) has been created that contains just the UI extensions. This does make the code much clearer as well as allowing for a leaner application if you're uninterested in UI bindings. I plan to make a more detailed post about the new ReactiveCocoa framework later on. For now, suffice it to say that UI objects (such as UITextFields, UIButtons, and so on have a property called .reactive that exposes signals with the various events. For example, the UITextField has a .reactive.continuousText signal, which sends an event with the textfield's text every time it changes. In the example below, the text of a UITextField is converted to upper case.
            .map { (text) -> String in
                guard let string = text else {
                    return ""

  1. If the signal can send errors, observing result will return either an error or a value 
  2. e.g.: .throttle(TimeInterval(0.5), on: QueueScheduler.main) 


  1. Good article!
    Check my piece about Swift advantages: