ReactiveCocoa Tutorial – The Definitive Introduction: Part 1/2

Get to grips with ReactiveCocoa in this 2-part tutorial series. Put the paradigms to one-side, and understand the practical value with work-through examples. By Colin Eberhardt.

Leave a rating/review
Save for later
Share

As an iOS developer, nearly every line of code you write is in reaction to some event; a button tap, a received network message, a property change (via Key Value Observing) or a change in user’s location via CoreLocation are all good examples. However, these events are all encoded in different ways; as actions, delegates, KVO, callbacks and others. ReactiveCocoa defines a standard interface for events, so they can be more easily chained, filtered and composed using a basic set of tools.

Sound confusing? Intriguing? … Mind blowing? Then read on :]

ReactiveCocoa combines a couple of programming styles:

For this reason, you might hear ReactiveCocoa described as a Functional Reactive Programming (or FRP) framework.

Rest assured, that is as academic as this tutorial is going to get! Programming paradigms are a fascinating subject, but the rest of this ReactiveCocoa tutorials focuses solely on the practical value, with work-through examples instead of academic theories.

The Reactive Playground

Throughout this ReactiveCocoa tutorial, you’ll be introducing reactive programming to a very simple example application, the ReactivePlayground. Download the starter project, then build and run to verify you have everything set up correctly.

ReactivePlayground is a very simple app that presents a sign-in screen to the user. Supply the correct credentials, which are, somewhat imaginatively, user for the username, and password for the password, and you’ll be greeted by a picture of a lovely little kitten.

ReactivePlaygroundStarter

Awww! How cute!

Right now it’s a good point to spend a little time looking through the code of this starter project. It is quite simple, so it shouldn’t take long.

Open RWViewController.m and take a look around. How quickly can you identify the condition that results in the enabling of the Sign In button? What are the rules for showing / hiding the signInFailure label? In this relatively simple example, it might take only a minute or two to answer these questions. For a more complex example, you should be able to see how this same type of analysis might take quite a bit longer.

With the use of ReactiveCocoa, the underlying intent of the application will become a lot clearer. It’s time to get started!

Adding the ReactiveCocoa Framework

The easiest way to add the ReactiveCocoa framework to your project is via CocoaPods. If you’ve never used CocoaPods before it might make sense to follow the Introduction To CocoaPods tutorial on this site, or at the very least run through the initial steps of that tutorial so you can install the prerequisites.

Note: If for some reason you don’t want to use CocoaPods you can still use ReactiveCocoa, just follow the Importing ReactiveCocoa steps in the documentation on GitHub.

Note: If for some reason you don’t want to use CocoaPods you can still use ReactiveCocoa, just follow the Importing ReactiveCocoa steps in the documentation on GitHub.

If you still have the ReactivePlayground project open in Xcode, then close it now. CocoaPods will create an Xcode workspace, which you’ll want to use instead of the original project file.

Open Terminal. Navigate to the folder where your project is located and type the following:

touch Podfile
open -e Podfile

This creates an empty file called Podfile and opens it with TextEdit. Copy and paste the following lines into the TextEdit window:

platform :ios, '7.0'

pod 'ReactiveCocoa', '2.1.8'

This sets the platform to iOS, the minimum SDK version to 7.0, and adds the ReactiveCocoa framework as a dependency.

Once you’ve saved this file, go back to the Terminal window and issue the following command:

pod install

You should see an output similar to the following:

Analyzing dependencies
Downloading dependencies
Installing ReactiveCocoa (2.1.8)
Generating Pods project
Integrating client project

[!] From now on use `RWReactivePlayground.xcworkspace`.

This indicates that the ReactiveCocoa framework has been downloaded, and CocoaPods has created an Xcode workspace to integrate the framework into your existing application.

Open up the newly generated workspace, RWReactivePlayground.xcworkspace, and look at the structure CocoaPods created inside the Project Navigator:

AddedCocoaPods

You should see that CocoaPods created a new workspace and added the original project, RWReactivePlayground, together with a Pods project that includes ReactiveCocoa. CocoaPods really does make managing dependencies a breeze!

You’ll notice this project’s name is ReactivePlayground, so that must mean it’s time to play …

Time To Play

As mentioned in the introduction, ReactiveCocoa provides a standard interface for handling the disparate stream of events that occur within your application. In ReactiveCocoa terminology these are called signals, and are represented by the RACSignal class.

Open the initial view controller for this app, RWViewController.m, and import the ReactiveCocoa header by adding the following to the top of the file:

#import <ReactiveCocoa/ReactiveCocoa.h>

You aren’t going to replace any of the existing code just yet, for now you’re just going to play around a bit. Add the following code to the end of the viewDidLoad method:

[self.usernameTextField.rac_textSignal subscribeNext:^(id x) {
  NSLog(@"%@", x);
}];

Build and run the application and type some text into the username text field. Keep an eye on the console and look for an output similar to the following:

2013-12-24 14:48:50.359 RWReactivePlayground[9193:a0b] i
2013-12-24 14:48:50.436 RWReactivePlayground[9193:a0b] is
2013-12-24 14:48:50.541 RWReactivePlayground[9193:a0b] is 
2013-12-24 14:48:50.695 RWReactivePlayground[9193:a0b] is t
2013-12-24 14:48:50.831 RWReactivePlayground[9193:a0b] is th
2013-12-24 14:48:50.878 RWReactivePlayground[9193:a0b] is thi
2013-12-24 14:48:50.901 RWReactivePlayground[9193:a0b] is this
2013-12-24 14:48:51.009 RWReactivePlayground[9193:a0b] is this 
2013-12-24 14:48:51.142 RWReactivePlayground[9193:a0b] is this m
2013-12-24 14:48:51.236 RWReactivePlayground[9193:a0b] is this ma
2013-12-24 14:48:51.335 RWReactivePlayground[9193:a0b] is this mag
2013-12-24 14:48:51.439 RWReactivePlayground[9193:a0b] is this magi
2013-12-24 14:48:51.535 RWReactivePlayground[9193:a0b] is this magic
2013-12-24 14:48:51.774 RWReactivePlayground[9193:a0b] is this magic?

You can see that each time you change the text within the text field, the code within the block executes. No target-action, no delegates — just signals and blocks. That’s pretty exciting!

ReactiveCocoa signals (represented by RACSignal) send a stream of events to their subscribers. There are three types of events to know: next, error and completed. A signal may send any number of next events before it terminates after an error, or it completes. In this part of the tutorial you’ll focus on the next event. Be sure to read part two when it’s available to learn about error and completed events.

RACSignal has a number of methods you can use to subscribe to these different event types. Each method takes one or more blocks, with the logic in your block executing when an event occurs. In this case, you can see that the subscribeNext: method was used to supply a block that executes on each next event.

The ReactiveCocoa framework uses categories to add signals to many of the standard UIKit controls so you can add subscriptions to their events, which is where the rac_textSignal property on the text field came from.

But enough with the theory, it’s time to start making ReactiveCocoa do some work for you!

ReactiveCocoa has a large range of operators you can use to manipulate streams of events. For example, assume you’re only interested in a username if it’s more than three characters long. You can achieve this by using the filter operator. Update the code you added previously in viewDidLoad to the following:

[[self.usernameTextField.rac_textSignal
  filter:^BOOL(id value) {
    NSString *text = value;
    return text.length > 3;
  }]
  subscribeNext:^(id x) {
    NSLog(@"%@", x);
  }];

If you build and run, then type some text into the text field, you should find that it only starts logging when the text field length is greater than three characters:

2013-12-26 08:17:51.335 RWReactivePlayground[9654:a0b] is t
2013-12-26 08:17:51.478 RWReactivePlayground[9654:a0b] is th
2013-12-26 08:17:51.526 RWReactivePlayground[9654:a0b] is thi
2013-12-26 08:17:51.548 RWReactivePlayground[9654:a0b] is this
2013-12-26 08:17:51.676 RWReactivePlayground[9654:a0b] is this 
2013-12-26 08:17:51.798 RWReactivePlayground[9654:a0b] is this m
2013-12-26 08:17:51.926 RWReactivePlayground[9654:a0b] is this ma
2013-12-26 08:17:51.987 RWReactivePlayground[9654:a0b] is this mag
2013-12-26 08:17:52.141 RWReactivePlayground[9654:a0b] is this magi
2013-12-26 08:17:52.229 RWReactivePlayground[9654:a0b] is this magic
2013-12-26 08:17:52.486 RWReactivePlayground[9654:a0b] is this magic?

What you’ve created here is a very simple pipeline. It is the very essence of Reactive Programming, where you express your application’s functionality in terms of data flows.

It can help to picture these flows graphically:

FilterPipeline

In the above diagram you can see that the rac_textSignal is the initial source of events. The data flows through a filter that only allows events to pass if they contain a string with a length that is greater than three. The final step in the pipeline is subscribeNext: where your block logs the event value.

At this point it’s worth noting that the output of the filter operation is also an RACSignal. You could arrange the code as follows to show the discrete pipeline steps:

RACSignal *usernameSourceSignal = 
    self.usernameTextField.rac_textSignal;

RACSignal *filteredUsername = [usernameSourceSignal  
  filter:^BOOL(id value) {
    NSString *text = value;
    return text.length > 3;
  }];

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

Because each operation on an RACSignal also returns an RACSignal it’s termed a fluent interface. This feature allows you to construct pipelines without the need to reference each step using a local variable.

Note: ReactiveCocoa makes heavy use of blocks. If you’re new to blocks, you might want to read Apple’s Blocks Programming Topics. And if, like me, you’re familiar with blocks, but find the syntax a little confusing and hard to remember, you might find the amusingly titled f*****gblocksyntax.com quite useful! (We censored the word to protect the innocent, but the link is fully functional.)
Colin Eberhardt

Contributors

Colin Eberhardt

Author

Over 300 content creators. Join our team.