ReactiveCocoa and Swift: Better Together

This talk is a love story, about the coming together of an elegant concept and a beautiful language. Colin Eberhardt narrates his experiences with ReactiveExtensions and ReactiveCocoa, including a short practical guide to using ReactiveCocoa, and a look at the newest major release, ReactiveCocoa 3. It’s a talk with a happy ending: you’ll see that ReactiveCocoa very much supports the ethos of Swift, while Swift finally lets the beauty of ReactiveCocoa shine through. Together, they make an excellent couple!


ReactiveCocoa and Swift (0:00)

I’m going to be talking to you today about ReactiveCocoa and Swift, and how Swift has made ReactiveCocoa better. It’s going to be the story of my experiences, first with reactive extensions a number of years ago, and more recently, ReactiveCocoa. I’m also going to avoid the “M” word and the “F” word, and I’m going to try to avoid words with the letter “E” in them.

No, I was only joking. I’m not going to do that.

A First Experience of Reactive Extensions (0:22)

This is taking me back a number of years. This is something I wrote 5 years ago using a technology called Silverlight. Does anyone remember Silverlight? So Silverlight was a technology that Microsoft developed to kill Flash, and, ironically, it wasn’t Microsoft that killed Flash, it was Steve Jobs and the iPad…

Anyway, this is something that uses reactive extensions. It’s a silly little application. What it does is query Twitter for the #uksnow hash map. If you tweet #uknow you can put in a postcode and the level of snow at that postcode. We’re weather obsessed in Britain! This is a bit of a mashup; using Bing Maps it will actually plot, in real time, where it’s snowing. Which only really works every now and then.

That was my first experience with reactive extensions. I thought they were brilliant and you will see why shortly.

ReactiveCocoa and Swift (1:13)

When I moved to iOS development, I think a couple of years ago, I was really pleased to see ReactiveCocoa. Developed by a group of great people at GitHub, it was directly inspired by reactive extensions. It was great to see this concept moving from one language to another.

I wrote a few articles on the Ray Wenderlich website; he kindly called them ‘The Definitive introduction’. ReactiveCocoa is really great but there are some things about the Objective-C language which marred the elegance of ReactiveCocoa and the whole approach. This is one of them. If you don’t understand this reference, you will do shortly. And you must have seen this one. All the ones with the little link at the bottom? I will be posting the links at the end, though you can probably guess what the little asterisks mean.

This is a story about how ReactiveCocoa has been improved, about how ReactiveCocoa has been able to show its real beauty through the Swift language. But also, about how it compliments in the other direction, how ReactiveCocoa is very much in keeping with the philosophy of Swift. If you’ve never done ReactiveCocoa before — actually, show of hands, who’s used ReactiveCocoa? I’d say about half of you here — I want to take everyone along on a journey.

ReactiveCocoa, a Brief Introduction (2:26)

These are only twenty minute talks, so I’m going to give you a very brief introduction to ReactiveCocoa. Half of you can go to sleep for a little while. You might have seen ReactiveCocoa described like this in the past: a combination of two different concepts, functional programming which I’m assuming everyone here is quite comfortable with now — it’s central to the Swift language — and this other thing called Reactive Programming, which is a focus on data flows. Put the two together and you get Functional Reactive Programming.

I find the sort of conceptual description of it quite difficult to understand. What I’d prefer to do is describe it in slightly more real and practical terms. Every line of code we write is executed as a reaction to some kind of event. This can be, for example, a user tapping a button, it can be a network request returning, it can be an application life cycle event. Code doesn’t execute itself, something has to happen to make the code execute.

But, the problem we have is, these events all have different forms. They’re all implemented in a different way; KVO, NSNotification, Delegate, Target Action, Block-Based Callbacks - they all have different forms, although fundamentally they’re all the same kind of thing: they’re an event that results in an execution of code.

ReactiveCocoa provides a common interface for all events, which is a great thing. Everyone can relate to that; having the same interface makes it much easier to write code. Removing the differences between KVO, NSNotifications and so on, and making them common, makes it easier to write code. But, it’s a lot more powerful than that. Once you have a common interface, you can then define a slightly higher level language for manipulating, transforming and co-ordinating events. You can form a language that works on top of all of these different events.

ReactiveCocoa in Action (4:41)

Let’s have a look at how this works in action. Now, I’m going to apologize straight away, there’s actually going to be a fair bit of Objective-C coming up in these slide. It hurt me just as much as it’s going to hurt you.

RACSignal *textSignal = [self.usernameTextField rac_textSignal];

[textSignal subscribeNext:^(id x) {
NSLog(x);
}];

This is simple bit of ReactiveCocoa. What we have here is a username text field, so it’s a UITextField, and, with ReactiveCocoa, it exposes a thing called a “text signal”. We’re subscribing to the text signal, and whenever the signal emits a next event, it’s going to log. Don’t worry, that might sound like gibberish. I’m going to explain things as we go along. First, just look at what happens. As I’m typing into the text field, it’s logging the output. Not terribly exciting, but I’ll start to explain some of the terms. What you saw was a subscription to a “signal”. Signals are emitters of events, and they can have multiple observers. There are some very simple rules that govern these events. There are three event types: next, error and completed. The simple rule is that a signal can emit none, one or more next events optionally followed by or terminated by an error, or completed. You can see a couple of simple examples there. The first one just completes immediately, the next one emits a couple of next events and errors, and the final one just emits a never ending stream of next events.

Signal All Things! (6:29)

You might start to see similarities here between some of the previous talks. I forget the terminology — whether he was using Promises or Futures — but the concept of Promises or Futures is something that will either return a success or a failure. There are some real similarities here. But the great thing is, you can signal all things. Anything asynchronous, or anything event based, can be modeled as a signal.

Let’s take a few examples. Say you have a network request, how is that going to look in the signal world? A network request where you request some data from a URL — it could be the BananaKit GitHub repository — will be returned to you as a single next event, carrying the data, followed by completed for the success scenario. What about a large download where there’s lots and lots of data? That might be returned to you as multiple next events, each one bringing the next chunk of data, again, followed by a completion. Or, if you look at a completely different application, what about UIKit? How about a button? This could be considered an infinite stream of next events. Again, it’s the same concept, able to model a wide range of different things.

A Higher Level Language (7:25)

Let’s get back to the code. I mentioned that once you’ve modelled everything using the same interface — the signal interface — you can define a slightly higher level language on top of it. You’re going to see some things here that are now incredibly familiar to you as Swift developers, but back in the old Objective-C kind of messy style.

RACSignal *textSignal = [self.usernameTextField rac_textSignal];

RACSignal *filteredText = [textSignal filter:^BOOL(NSString *text) {
	return text.length > 3;
}];

[filteredText subscribeNext:^(id x) {
	NSLog(x);
}];

Here, what we’re doing is taking our text signal and filtering it. Here, we’re using the block-based syntax. We’re filtering it to return the Boolean — it’s a block — and whenever the length of the string is greater than four, it’s true, otherwise it’s false, and we’re subscribing to the result. I think you can all probably guess what that does. As you type in, it’s logging; but when the length of the string is less than four, the logging stops.

Events (8:11)

So far I’ve described signals. I haven’t really told you what events are and you might be thinking “What are they? And what do they look like?”. The interesting thing is they can be anything and that’s what makes it so powerful. The next event doesn’t have a specific shape. In this case it’s providing strings, but in other applications it could provide a dictionary which is a representation of JSON. It can be anything you like.

RACSignal *textSignal = [self.usernameTextField rac_textSignal];

RACSignal *textLength = [textSignal map:^id(NSString *text) {
	return @(text.length);
}];

[textLength subscribeNext:^(id x) {
	NSLog(@"%@", x);
}];

What ReactiveCocoa does is provide you with a framework for handling these streams of data. Let’s have a look at another example: map – another thing that you’re very familiar with. This time we’re taking the text signal, and through the map operation we’re converting it into the length of the string. You’ll see the output is quite different. As the text is being typed in, you’re seeing the length of the string being logged. Of course, you can combine these and keep going further and further, performing more operations on them, but the important thing to point out here is that, at each step, every time you perform an operation, you are getting back a signal. So, what you can do – in one of the previous talks a speaker showed exactly this application – you can remove the intermediate assignments and you can chain it all together. This is something that in other languages, and I guess to a certain extent in Objective-C and iOS, is termed a “fluent API”. A fluent API is anything where the operation returns the object itself. That’s what allows you to chain them, one upon the other. It’s tremendously popular in languages like JavaScript. If you’ve done any JavaScript you’ll no doubt have done JQuery, you might have done D3. It’s very popular in C# with things like Link. It’s not so popular in Objective-C.

This reminds me a little bit of Chris’ talk, where he showed how the flow of a view controller can be modeled using the pipe operator. Here we’re showing a different kind of flow; but what’s so great about it is you can immediately and visually see the flow of an application in one place. If we throw away the code and draw a little diagram, this is the underlying application flow. We’ve got a signal which emits a string, we’re mapping it to create a number, we’re filtering that number, thn we’re subscribing to the result and logging the output. Again this is a pretty trivial case, but you can see how, with these tools, you can build much more complicated applications.

This is an application I’ve put on GitHub which, again – it’s the classic thing – searches Twitter. I’m not going to go over it in too much detail, but the green boxes are signals, they are operations that allow you to manipulate, merge, and control different signals. The blue items allow you to control different signals, and the purple ones are end points — ones where you take the result of one of the signals and do something with it. This is the actual code that models the pipeline – again, don’t try to read it all. The great thing about this is the overall shape. You can actually read the flow of the application from top to bottom. I think, despite the Objective-C syntax here, it’s quite beautiful.

“Railway Oriented Programming” (11:06)

There are also elements of “Railway Oriented Programming”, mentioned in Brian’s talk. That, to be honest, is a new term to me, but it’s not a new concept. You’ll notice, down at the bottom, the error. If you go off the success path and fall into the failure path, it’s always collected at the bottom there. And this is combining multiple signals, so it doesn’t matter which signal fails. We have our failure, where you go off the correct path, and it’s collected at the end.

Here it is, up and running. I’m searching Twitter for Swift and realizing “Oh, hang on, Taylor Swift. Wrong Swift”. So I’m going to search for Swift Language – you might see some faces you recognize on here. What this is also doing is using sentiment analysis. As the tweets become visible, it’s using a bit more ReactiveCocoa to fetch the sentiment. Oh look, Microsoft! There’s some hate for Microsoft there, that’s good. The least said the better. As you can see, I think ReactiveCocoa - the general concept there - is fantastic, but as I’ve mentioned, it’s marred by the the syntax Objective-C.

I apologize if you’ve seen this joke before, but I’m a bit like a child; I find the same joke funny again, and again, and again. This was something I found on Stack Overflow. I use Stack Overflow a lot to write my code for me. This person asked about the fluent interface pattern in Objective-C. Basically: “I’m a newbie in Objective-C, and I would like to implement the fluent interface pattern.” This was the best response [shows response]. Hopefully now you can relate to the square brackets I showed at the beginning of the talk.

Swift Makes Everything Better (13:27)

That was the first part of my story, when I first encountered ReactiveCocoa. It was really well documented, a great framework, I loved it immediately. Then things got a whole lot better when Swift came along. They became better quite immediately.

Obviously you could take the Objective-C code, bridge it to Swift, burn those brackets, and this is what you get back in return. This is better for a couple of reasons. The first one is the use of dot notation rather than leading and trailing square brackets — I’ve never understood that. The second one is the closure expression syntax. It’s much more succinct than the block-based equivalent. To my mind this brings iOS development up to date. It brings it up to date with languages like C# that have lambda expressions. And languages like JavaScript, which has arrow functions. A lot of other languages have been doing this for a while. It’s great, it brings us up to speed.

I’m actually using a slight of hand here. filterAs, flattenMapAs, and subscribeNextAs are little shims that I’ve placed in there, because, as I mentioned, next events can be anything. In the previous examples, what I had to do was cast. I have to know, “ok, I’ve got a signal which is providing me with some text, so I’m going to cast”. This is not terribly safe. Here, I’ve basically done that behind the scenes: I’ve created a closure expression with a type, which is then being used to perform the cast in the background. I’m letting you know that I’m pulling a fast one on you there.

The Love Goes Both Ways (14:57)

The love goes both ways. As I mentioned, Swift has made ReactiveCocoa a much more elegant framework, but also, ReactiveCocoa is quite complimentary to the Swift mindset. Swift encourages immutability. As we all know, it makes code easier to test, it reduces bugs, in short it’s very useful. The application I showed you had 51 variables, but that’s not quite the truth: it actually had 39 constants, which is a great thing! Only 12 variables, and of those 12 variables, 6 of them were outlets – not my fault – one of them was a UIWindow – again, not me – and the final ones: 5 UI state variables, which are pretty much unavoidable. Although ReactJS and ReactNative might have a different perspective on that. Clearly this does good things for your code.

ReactiveCocoa 3 (15:50)

The final thing I want to talk about is ReactiveCocoa 3. This is something that the ReactiveCocoa team started working on quite a while back… I think it was late 2013… But when Swift came along, obviously they saw a huge opportunity, and pretty much halted development and started working on Swift. Although, having said that, it wasn’t a complete change of direction: what they were doing with ReactiveCocoa 3 was performing quite a lot of simplifications. What I’ve shown you so far have been the very well used, good bits of ReactiveCocoa. There have been other bits around the edges, things like the command pattern, which haven’t really been well adopted. So they’re looking at reshaping some of those things, to hopefully improve the adoption of other parts of the framework.

Significant Changes (16:59)

Let’s have a look at what it looks like in Swift. This is probably the most significant change: it doesn’t have RAC in front of signal. No, sorry, that’s not the most significant. It’s the use of generics, that’s the most significant change. We have two type parameters: we’ve got T, which is the type of the object being emitted by the signal, and we have an ErrorType as well. How does this look? This was my ReactiveCocoa 2 bridge to Swift with a little bit of a shim, and this is what it looks like in ReactiveCocoa 3. Again, I don’t want you to read it all. I feel a bit like an Optician, “Do you prefer…this? Or this?”. So what’s changed? A big, big change here is there’s no need to cast anymore, because signals are now, effectively, strongly typed. The closure expressions don’t have to cast because of your knowledge of what is being emitted by the signal. You can also use short hand arguments. I must point out, some of these bits, things like flattenMap, I’m still navigating myself around the 3 API’s and I have a feeling I should be using joinMap there.

The Pipe Forward Operator (17:55)

Probably the other most significant thing you’ll notice is that weird looking operator on your left-hand side. This is a pipe forward operator, |>. It’s not something they have conjured up themselves, the pipe forward operator is something that already exists in languages like F#. It’s a funny looking beast, and I’ll quickly show you what it does and why it exists. Now, what you might expect is for signal to have a map operation actually implemented as a method. That’s not the case. What they’ve done is they’ve made map, filter and so on, free functions. I’ve been trying to get my head around why they’ve been doing this, and one of the advantages of having them as free functions is that you can define them on protocols rather than concrete types. So you are free from the constraints of type hierarchies, although they haven’t actually used that here. If anyone has any other great ideas about why they’re doing this, I’m learning too.

The net result is, if you want to map something, it might look like this. If you want to map it again, it might look like this. If you want to map it again? Sad face. This has, all of a sudden, meant that we are no longer getting that lovely, fluent, syntax.

let mapped = map(signal, { $0.foo }) //map once
let mapped = map(map(signal, { $0.foo }), { $0.bar }) //map twice
let mapped = map(map(map(signal, { $0.foo }), { $0.bar }), { $0.sadface })

So what they’ve done is they’ve used the awesome power of curried functions, and now map is a function where you can partially apply it, giving the transform, then you get back a function which takes a signal and returns a signal. And they’ve got this fantastic operator here that I cannot possibly explain to you.

public func |> <T, E, X>
	(signal: Signal<T, E>, transform: Signal<T, E> -> X) -> X {
 		return transform(signal)
	}

I’ve created a playground with a simplified version, where I’ve created a new typed called Stringy. It’s a string which has a fluent interface. If you have a look at this playground, it shows you how an append method works as a method, as a free function, as a curried free function, with a pipe forward operator. This is how I got my head around it. But the best thing about the playground is my operator here, the best thing isn’t all the clever stuff with curried functions, it’s the fact that it looks a little bit like a fish.

A Happy Story (19:47)

That’s pretty much it from me. This talk has been the story of an evolution of something I’ve greatly enjoyed in one language coming to another, a story of how the introduction of Swift has made ReactiveCocoa, and the concepts of reactive extensions, better. It’s also the story of how ReactiveCocoa has given back to Swift, of how it’s supporting the general concepts and the ethos. I think it’s a great story. It’s one of these journeys that I’ve very much enjoyed going on.

Hopefully, if you haven’t had a go with ReactiveCocoa, this has inspired you to give it a go yourself.

Thanks for listening!



Colin Eberhardt

Colin Eberhardt