A bit of preamble...
This post was written about a year ago, shortly after the announcement of Swift at WWDC 2014. I'm afraid much of the code below is out of date, and will likely remain so for a while yet. I hope that it's still useful, but please don't consider it reflective of current "best practices" in swift or ReactiveCocoa, which are both approaching new major versions (swift 2 and ReactiveCocoa 3) and have undergone major changes in the past year. Thanks!


As I'm writing this, Apple's new programming language Swift has been public for less than two weeks. To say it has drawn a lot of interest would be an understatement. As one of the thousands of developers intrigued by this shiny new tool, I naturally jumped right in and started writing some Swift code.

So far it's been pretty great. Syntactically it's a breath of fresh air after spending years in the square-bracket mines. Just being able to write closures without having to deal with the maddening block syntax is amazing. There are some semantically interesting things too, like support for immutable values, the excellent enum type, and the "optional" type. Working with Swift has been fun, and if you already know Cocoa, it's pretty easy to get started with.

There have been a few rough edges, which isn't too surprising given how brand new the language is. Most of the problems I've encountered so far have to do with the interoperability with Objective C, which sometimes doesn't want to play nice with Swift's type inference system. Mostly though it's been a lot of fun, and I'm convinced that Swift will eventually replace Objective C as the primary language for Apple's platforms.

I've decided to use Swift for a new app that I'm working on, and as I was hard at work in my business hammock thinking about the broad design of the thing, I came across ReactiveCocoa, a framework for doing functional reactive programming (FRP) in Cocoa.

The big idea behind FRP in general and ReactiveCocoa in particular is that you can write your programs as a declarative set of transformations of values over time, rather than keeping track of tons of transient state in instance variables and so on. You process inputs (taps, keyboard inputs, network events, etc) as "signals", whose values can be transformed using functions such as filter and map, and combined to produce new values as output. All the logic for translating the many sources of input in your app into some action can be contained in a single set of transformations along the signal chain. It's cool.

ReactiveCocoa is so self-evidently awesome that it has naturally attracted a lot of attention, and there are some excellent resources for learning the ins and outs. The NSHipster article provides a good overview of what the Framework is all about (much better than I've done, certainly).

Another great resource is Colin Eberhardt's excellent raywenderlich.com tutorial. I've been working on getting it ported over to Swift, and throughout this post I'll be going through what I've learned along the way, using Part One of the original tutorial as a reference.

I'm just going to assume that you've picked up the basics of Swift, but if not, there are plenty of fine resources available:

The Basics

Swift and ReactiveCocoa seem like a perfect fit. Swift is designed with first-class functions and a succinct closure syntax, and ReactiveCocoa is all about implementing data flows using closures, in the form of Objective C blocks. Since blocks map onto Swift closures, it should be simple to get them playing nice, right?

Or, not…

There are a few problems right at the outset. Just including ReactiveCocoa in a Swift project and trying to build it will currently give you a nice, friendly compiler error. ReactiveCocoa defines methods on the RACSignal class called "and", "or", and "not". This breaks the compiler. Which is odd, since none of those words are reserved keywords in either Objective C or Swift. It seems like it's a compiler bug, but until it's sorted out we need to work around it. The simplest solution is to go to their definitions, right click on the offending keyword and select "Refactor > Rename…" from the context menu. Then enter a new name. I decided to just use the uppercase version of each word, so the methods are now named "AND", "OR", and "NOT".

Now we can get going. If you haven't looked at the original tutorial, here's a quick overview of the app we're building. It is a simple sign in form with username and password fields and a log in button. Invalid entries for each field cause the field to have a yellow background color to highlight the error, and the log in button is only enabled when both fields contain valid input. When you enter the correct username and password (hard-coded as "username"/"password"), you are rewarded with a picture of an adorable kitten! Invalid credentials will display an error message instead.

Lets just gloss over making the Storyboard and get started with the code. If you'd like to follow along, my finished Swift version is available at my github. The repo includes a fork of ReactiveCocoa as a submodule with the refactor already applied, so no need to fix it up.

In our ViewController class we have a few @IBOutlet decorated properties for the interface elements, and an instance of our fake sign-in service that we'll be using later. There are also a few helper functions, and then we get to the heart of the thing, the viewDidLoad() function.

In the original Objective C version, we create some signals to indicate whether the username and password fields are valid:

RACSignal *validUsernameSignal =  
  [self.usernameTextField.rac_textSignal
    map:^id(NSString *text) {
      return @([self isValidUsername:text]);
    }];
 
RACSignal *validPasswordSignal =  
  [self.passwordTextField.rac_textSignal
    map:^id(NSString *text) {
      return @([self isValidPassword:text]);
    }];

In Swift, that translates to:

var validUsernameSignal =  
    usernameField
        .rac_textSignal()
        .map { self.isValidUsername($0) }


var validPasswordSignal =  
    passwordField
        .rac_textSignal()
        .map(isValidPassword)

Not bad! It's certainly more succinct, and I find it much easier to read. Notice that we're using two different styles of invocation here. For the username signal, we're passing in a closure which calls a helper function, using the trailing closure syntax. For the password signal, we pass the helper function in directly by name. This is possible because Swift functions are a special case of closures, and they can be used interchangeably. We do have to make sure that the isValidPassword function has the argument and return types that the map method expects. Since map takes a block that accepts an id and returns an id, we need to make sure our argument type is AnyObject! and our return type conforms to the AnyObject protocol.

func isValidPassword(name : AnyObject!) -> NSNumber! {  
  return (name as NSString).length > 3;
}

So that's nice. Next, we'd like to set the "backgroundColor" property of our text fields to reflect whether they contain valid input.

One way is by mapping to a UIColor, then using "subscribeNext" to perform an action when the mapped signal has a value:

validUsernameSignal.map {  
  let valid = $0 as Bool
  return valid ? UIColor.clearColor() : UIColor.yellowColor()
}
.subscribeNext {
  self.usernameField.backgroundColor = ($0 as UIColor)
}

However, there is a cleaner way to accomplish this, which we'll explore next.

Operator overload

When using ReactiveCocoa, you'll often find yourself wanting to update a property with the value of a signal. This is such a common desire that it's built into the framework in the form of the RAC macro. In the original tutorial it is used like this:

RAC(self.passwordTextField, backgroundColor) =  
  [validPasswordSignal
    map:^id(NSNumber *passwordValid) {
      return [passwordValid boolValue] ? [UIColor clearColor] : [UIColor yellowColor];
    }];

On the left-hand side of the = sign we give the RAC macro the name of an object and one of its properties. On the right-hand side, we have a RACSignal. In the example, we're processing an existing signal (validPasswordSignal) and transforming it with a map operation so that it returns a different UIColor depending on whether the password text is valid or invalid.

This looks like an assignment operation, but what are we actually assigning to? Whatever it is, we certainly don't have a reference to it, nor do we need one. What we're interested in are the side effects of the assignment, namely whatever bit of magic actually wires up the property to the signal. This looks a lot like operator overloading; we're triggering some custom action on the use of a built-in operator. However, Objective C doesn't support operator overloading. What's going on here?

Fun with trampolines

Let's take a look at how the RAC macro works. Here's its definition:

#define RAC(TARGET, ...) \
    metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__)) \
        (RAC_(TARGET, __VA_ARGS__, nil)) \
        (RAC_(TARGET, __VA_ARGS__))

/// Do not use this directly. Use the RAC macro above.
#define RAC_(TARGET, KEYPATH, NILVALUE) \
    [[RACSubscriptingAssignmentTrampoline alloc] initWithTarget:(TARGET) nilValue:(NILVALUE)][@keypath(TARGET, KEYPATH)]

The first macro just calls the second RAC_ macro with a default value of nil for the third argument. The RAC_ macro is where the magic happens. Calling RAC_(myObject, propertyName, nil) expands to this:

[[RACSubscriptingAssignmentTrampoline alloc] initWithTarget:myObject nilValue:nil][@"propertyName"]

Hmm… First, we're creating an instance of RACSubscriptingAssignmentTrampoline and initializing it with two of the values from the RAC macro: the object we care about and the optional "nil value".

The name RACSubscriptingAssignmentTrampoline kind of gives away the game. Immediately after the alloc/init comes another set of square brackets, this time with a string inside. In case you're not familiar, Apple added dictionary literal syntax to Objective C a while back. Square brackets with an object inside translates to a dictionary lookup. For example, you can get a value in an NSDictionary like this:

NSString *str = myDict[@"someKey"];  

What's interesting is that this operator can be overloaded. If your class provides an implementation for - (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key, that method will be called when someone tries to set a value using the subscript operator syntax. Whatever is on the right hand side of the = sign will be passed in as obj, and whatever is in the brackets will be passed in as key.

ReactiveCocoa is essentially using a permitted operator overload to approximate a forbidden one. By using the subscript syntax they can overload the assignment with custom behavior, but by using a macro they can hide the messy details from the caller. The actual implementation of the subscript operator method is pretty trivial:

- (void)setObject:(RACSignal *)signal forKeyedSubscript:(NSString *)keyPath {
    [signal setKeyPath:keyPath onObject:self.target nilValue:self.nilValue];
}

All it's doing is calling a method on signal (the thing on the right-hand side of the assignment) with the key path in the brackets, plus the values that were passed in to initWithTarget:nilValue earlier.

Pretty sneaky, ReactiveCocoa!

Doing it Swiftly

So, since we're working in Swift, we've got a bit of a problem. Namely, Swift doesn't support macros. It does support very simple conditional compilation of the #if / #else type, but not the more complicated text-substitution macros of the C preprocessor. However, we don't need macros to approximate operator overloading when we've got the real deal!

First, let's implement the basic functionality before we start getting all crazy with operators.

struct RAC  {  
    var target : NSObject!
    var keyPath : String!
    var nilValue : AnyObject!

    init(_ target: NSObject!, _ keyPath: String, nilValue: AnyObject? = nil) {
        self.target = target
        self.keyPath = keyPath
        self.nilValue = nilValue
    }


    func assignSignal(signal : RACSignal) {
        signal.setKeyPath(self.keyPath, onObject: self.target, nilValue: self.nilValue)
    }
}

We use the same name as the RAC macro for familiarity's sake. Fortunately, they won't collide, since Swift doesn't support macros and Objective C doesn't support Swift structs. Everything is pretty simple, although you might notice that the init has underscores before the first two parameter names. This is saying we don't want external names for our parameters, so that we can call RAC(myObject, "propertyName") instead of RAC(target: myObject, keyPath: "propertyName"). I decided to leave the external name for nilValue, since it seems like something that you'd want to be explicit about. Another thing to note is that we have to pass in the keypath of the property we're interested in as a String, because passing a bare identifier as we did with the preprocessor macro would cause a compilation error.

So now, we can get essentially the same functionality as the macro by doing:

RAC(myObject, "propertyName").assignSignal(mySignal)  

But where's the fun in that? Lets get our hands dirty with some operator overloading!

Swift won't let us overload the assignment operator, but I personally don't think it's the greatest fit anyway. We're not assigning a single value, but a stream of values that change over time. After some head-scratching, I settled on the <~ operator to "feed" a signal into the RAC construct. The tilde character looks kind of like a sine wave if you squint a bit, so that seemed like a good fit for "signal" and the arrow indicates the direction that the signal is flowing.

The definition looks like this:

operator infix <~ {}  
@infix func <~ (rac: RAC, signal: RACSignal) {
    rac.assignSignal(signal)
}

And now we can use it much like the old RAC macro:

RAC(myObject, "someProperty") <~ someSignal  

But why stop there? Since we have the ability to define our own operators, we can make the signal flow the other direction too:

operator infix ~> {}  
@infix func ~> (signal: RACSignal, rac: RAC) {
    rac.assignSignal(signal)
}

Now we can put the signal on the left and the RAC construct on the right, like so:

someSignal ~> RAC(myObject, "someProperty")  

Neat, huh?

Reductio ad absurdum

Now that we've got the RAC construct all sorted, lets keep banging away at that tutorial.

Right now our ViewController class looks like this:

import UIKit

class ViewController: UIViewController {

    @IBOutlet var loginField : UITextField!
    @IBOutlet var passwordField : UITextField!
    @IBOutlet var loginButton : UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        var validUsernameSignal =
            usernameField
                .rac_textSignal()
                .map { self.isValidUsername($0) }

        var validPasswordSignal =
            passwordField
                .rac_textSignal()
                .map(isValidPassword)

        RAC(self.loginField, "backgroundColor") <~ validLoginSignal.map(colorForValidity)
        validPasswordSignal.map(colorForValidity) ~> RAC(self.passwordField, "backgroundColor")

    }

    // Helper functions
    func isValidUsername(name : AnyObject!) -> NSNumber! {
        return (name as NSString).length > 3;
    }

    func isValidPassword(pass : AnyObject!) -> NSNumber! {
        return (pass as NSString).length > 3;
    }

    func colorForValidity(valid : AnyObject!) -> UIColor! {
        return (valid as Bool) ? UIColor.clearColor() : UIColor.yellowColor()
    }

}

This all works pretty well. The text fields start out yellow and turn white when you enter valid input (here defined as more than three characters). Next up is enabling the log in button only when we have valid input for both fields. The next part of the tutorial has us combining the signals validLoginSignal and validPasswordSignal using a class method on RACSignal called + (RACSignal *)combineLatest:reduce:.

ReactiveCocoa implements the reduce functionality using some extremely tricky details of the Objective C language. Here's the declaration of the combineLatest:reduce: method:

+ (RACSignal *)combineLatest:(id<NSFastEnumeration>)signals reduce:(id (^)())reduceBlock;

The comments in the header have this to say about the reduce block:

/// reduceBlock - The block which reduces the latest values from all the
///               signals into one value. It must take as many arguments as the
///               number of signals given. Each argument will be an object
///               argument. The return value must be an object. This argument
///               must not be nil.

Huh? The method accepts a block with no parameters, but expects you to provide a block with the same number of parameters as the number of signals you pass in. What the hell?

It turns out that this is a feature of Objective C blocks that I've never encountered before. If you declare a block type with an empty parameter list, you can assign a block with any number of parameters to it. I had no idea. This isn't usually that useful, since when you want to call the block, you need to supply the right number of parameters, and the block definition doesn't help you there.

Once again, ReactiveCocoa is being extremely sneaky. Since they know how many signals are provided, they just call the block with that number of arguments. If you're interested in the specifics, check out RACBlockTrampoline.m in the source.

Well, that kite won't fly in Swift. The Swift compiler refuses to pass a closure that accepts arguments to a method expecting a block with zero arguments. I tried a few different horrible hacks to try to force it to work, but I just couldn't get the compiler to swallow it.

Luckily, Swift is kind enough to provide its own reduce() function, as a method on the Array class. Lets see how we can use it with signals.

We can call combineLatest: without the reducer, in which case it will combine the signals into a new value. That value is a RACTuple which contains each of the signals. We can convert that to an Array and reduce it like so:

let signupActiveSignal =  RACSignal.combineLatest([validUsernameSignal, validPasswordSignal]).map {  
    let tuple = $0 as RACTuple
    let bools = tuple.allObjects() as Bool[]
    return bools.reduce(true) {$0 && $1}
}

Here we're mapping the RACTuple returned by RACSignal.combineLatest() to a single Bool, by first casting tuple.allObjects() to a Bool[] and then reducing it using a very simple reducer that just returns the logical AND of the two arguments.

One advantage of doing the reduce this way is that we can change the number of arguments without having to change the reduce block. This is because our reduce block operates on each value one at a time, passing the result of each invocation into an accumulator (the first parameter to the reducer). We can have any number of values and they'll all be processed in turn.

However, the restriction is that all the values being reduced must be of the same type. This is probably going to be the case anyway, but if you were combining signals with different value types, you'd just need to unpack them from the RACTuple and do whatever you needed with them. Something like this:

RACSignal.combineLatest([thisSignalHasABool, thisOneHasAString]).map {  
    let tuple = $0 as RACTuple
    let boolVal = tuple.first() as Bool
    let strVal = tuple.second() as String

    // do something with boolVal and strVal
}

Take a look at RACTuple.h to see what kind of things you can do with a RACTuple.

Finally, it should be noted that we can avoid all this reducing nonsense entirely in this particular case. Since all we're really after is the logical AND of a collection of Bools, we can use the convenience AND method on RACSignal. Remember that guy, who's name we had to upcase from "and" to make the Swift compiler happy? Well, it does exactly what we want, returning the logical AND of a collection of NSNumber containing signals. Since Bool is bridged to NSNumber, it works out of the box.

So we can change our statement to this:

let signupActiveSignal =  RACSignal.combineLatest([validUsernameSignal, validPasswordSignal]).AND()  

Works a treat, but it's nice to know how to reduce things when you have a more complicated operation you'd like to perform across a collection of signals.

Action!

Let's make something happen when we press our sign in button. We'll be using ReactiveCocoa's extension to UIControl, rac_signalForControlEvents.

loginButton.rac_signalForControlEvents(UIControlEvents.TouchUpInside)  
    .subscribeNext {
        _ in
        println("Button pressed!")
    }

The _ in is there so that the type inference system will kick in. If you don't reference the parameters at all, Swift will assume your closure doesn't accept any, which wouldn't be compatible with the subscribeNext method.

Now if we touch up inside the button we get a log message. Getting it to sign in is a bit more involved, but since this post is getting long enough already, I'm just going to jump to the finished product. For more on the reasoning behind this approach, see the original tutorial.

In viewDidLoad():

loginButton.rac_signalForControlEvents(UIControlEvents.TouchUpInside)  
    .doNext {
        _ in
        self.loginButton.enabled = false
        self.signInFailureText.hidden = true
    }
    .flattenMap(signInSignal)
    .subscribeNext {
        let success = $0 as Bool
        self.loginButton.enabled = true
        self.signInFailureText.hidden = success
        println("Sign in result: \(success)")
        if success {
            self.performSegueWithIdentifier("signInSuccess", sender: self)
        }
    }

The doNext block executes first and resets the state of the sign in button and failure text. Since it doesn't return a value, the original signal passes unchanged into flattenMap, which sends it through the signInSignal() function:

func signInSignal(_ : AnyObject!) -> RACSignal {  
    return RACSignal.createSignal {
        subscriber in
        self.signInService.signIn(self.usernameField.text, password: self.passwordField.text) {
            subscriber.sendNext($0)
            subscriber.sendCompleted()
        }
        return nil
    }
}

As its name suggests, signInSignal() returns a new signal, one which contains the result of calling out to the sign in service. Since it returns a signal, we use flattenMap instead of a plain old map, which will send the value of the signInSignal to the subscribeNext block.

The subscribeNext block just checks that value and either shows the failure text or performs a segue to show the kitten. Thanks to ReactiveCocoa, all of the logic from button press to segue is contained in one signal chain.

Winding up

I have no doubt that the ReactiveCocoa project will be quick to adapt to Swift, most likely rewriting the ReactiveCocoa primitive types in Swift directly. Until then, it's certainly possible to use ReactiveCocoa in a Swift project today, although you may find yourself working around some of the rough edges of Objective C / Swift interoperability. Personally, I think it's well worth the bit of effort.