ReactiveCocoa
Bob Spryn
LoHi Labs
@sprynmr (github, twitter)
!
!
!

https://github.com/ReactiveCocoa/ReactiveCocoa
ReactiveCocoa
•

An implementation of functional reactive programming

•

It provides APIs for composing and transforming
streams of values

•

“Signals” send you these values over time for you to
react to

http://en.wikipedia.org/wiki/Functional_reactive_programming
?
Not just another API.

It enables you to

Program Smarter
Focus on WHAT not HOW
Reactive!!! Declarative!!!

What does that even mean?
• Setup

your reactions

• Compose,

Reactive!!! Declarative!!!

split, filter, etc.

What does that even mean?
Imperative
The way we normally program.
Imperative
The way we normally program.

•

Observe, wait, then command & control

•

Dealing with the HOW, not just the WHAT

•

Code for controlling flow is spread all over
Auto-layout : Managing Frames
ReactiveCocoa : Imperative programming
Complexity
Is
STATE
BOOL loadingNextPageOfComments;

2 states


BOOL commentsAreShowing;

4 states


BOOL commentsLoadingShowing;

8 states


BOOL flippingAnswers;

16 states


BOOL isOwnerOfQuestion;

32 states
- (void) updateChangeAnswerButtonText {
if (self.didAnswerQuestion && self.inResultsView) {
[self.commentHeaderCell configureWithStyle:TCQuestionDetailCommentHeaderCellChangeAnswer];
} else if (self.isOwnerOfQuestion && !self.didAnswerQuestion && self.inResultsView) {
[self.commentHeaderCell configureWithStyle:TCQuestionDetailCommentHeaderCellViewAnswers];
} else {
[self.commentHeaderCell configureWithStyle:TCQuestionDetailCommentHeaderCellViewStats];
}
}
- (void) updateViewCommentStatus {
if ((self.didAnswerQuestion || self.isOwnerOfQuestion) && !self.commentsAreShowing) {
self.commentsAreShowing = YES;
- (void) prepareForReuse {
self.commentsLoadingShowing = YES;
self.state = TCQuestionDetailViewContro
…
self.questionFullyLoaded = NO;
}
self.isOwnerOfQuestion = NO;
self.didAnswerQuestion = NO;
[self showCommentBox:self.inResultsView || self.isOwnerOfQuestion];
[self showCommentBox:NO];
}
self.loadingNextPageOfComments = NO;
self.commentsAreShowing = NO;
self.commentsLoadingShowing = NO;

!

^aBlock {
sself.didAnswerQuestion = sself.question.userResponse ? YES : NO;
sself.inResultsView = sself.didAnswerQuestion || self.isOwnerOfQuestion;
if (sself.questionFullyLoaded) {
return;
} …

}

}

l co
Rea

rom
ef
d

file
one
ReactiveCocoa to the Rescue!

•

Signals instead of mutable variables


•

RACSignal – Think of it as a beacon sending out new values to it’s
subscribers
RACSignal
•

A unified interface for observing and reacting to all kinds of events
and their values

•

UI Action


•

Async Network Call


•

KVO


•

Async Processing

t’s
I

in
ll
a

t!
pu
RACSignal
•

Shared vocabulary for transforming the received values

•

•

Combine, filter, reduce, map, and many more operations


Eventually generate output (side effects)

•

Updating a label


•

Update an array with objects from the network


•

etc.
- (void)viewDidLoad {

[super viewDidLoad];

[self.username

addTarget:self

action:@selector(textFieldTextDidChange:)

forControlEvents:UIControlEventAllEditingEvents];

[self.email

addTarget:self

action:@selector(textFieldTextDidChange:)

forControlEvents:UIControlEventAllEditingEvents];


Your name
Your email address
Sign Up

abled
ton.en
ut

gnUpB
si

}
!

- (void)textFieldTextDidChange:(UITextField *)field {

BOOL validUsername = self.username.text.length > 0;




NSRange at = [self.email.text rangeOfString:@"@"];




BOOL validEmail = at.location != NSNotFound;

self.signupButton.enabled = validUsername &&

validEmail;

}

Old

Solved the imperative way.
Your name
Your email address
RAC(self.signUpButton, enabled) = [RACSignal
combineLatest:@[

self.name.rac_textSignal,

self.email.rac_textSignal

]

reduce:^(NSString *name, NSString *email) {

NSRange at = [email rangeOfString:@"@"];
return @(at.location != NSNotFound && name.length > 0);

}];

Sign Up
ould I
Sh

SOME
AWE

bled?
e ena
b

Solved the reactive way.
Your name
Your email address
RAC(self.signUpButton, enabled) = [RACSignal
combineLatest:@[

self.name.rac_textSignal,

self.email.rac_textSignal

]

reduce:^(NSString *name, NSString *email) {

NSRange at = [email rangeOfString:@"@"];
return @(at.location != NSNotFound && name.length > 0);

}];

Sign Up
ould I
Sh

SOME
AWE

bled?
e ena
b

Solved the reactive way.
Network Validation?
Easy.

Your name
Your email address
Sign Up

RACSignal *validateEmailSignal = [self.email.rac_textSignal
map:^id(NSString *emailString) {
return [MyAPI validatedEmail:emailString];
}];

uld I
Sho

bled?
be ena

!

RAC(self.signUpButton, enabled) = [RACSignal
combineLatest:@[

self.name.rac_textSignal,

validateEmailSignal

]

reduce:^(NSString *name, APIResponse *response) {

return @(response.json.isValid == YES && name.length > 0);

}];

SOME
AWE

Solved the reactive way.
Network Validation?
Easy.

Your name
Your email address
Sign Up

RACSignal *validateEmailSignal =
map
}];
!

uld I
Sho

The point is to Minimize State

RAC
combineLatest

]
reduce
}];

Solved the

SOME
AWE

bled?
be ena
Network Validation?
Easy.

Your name
Your email address
Sign Up

RACSignal *validateEmailSignal =
map
}];
!

uld I
Sho

The point is to Minimize State

RAC
combineLatest

]
reduce
}];

Solved the

SOME
AWE

bled?
be ena
Check out ReactiveCocoa
Your Brain Will Thank You
https://github.com/ReactiveCocoa/ReactiveCocoa

Bob Spryn
LoHi Labs
@sprynmr (github, twitter)
!

Thanks to @jspahrsummers, @joshaber, @AshFurrow, @robb, @andrewsardone and @erikprice (github usernames)
for sharing their presentation slides and helping me learn ReactiveCocoa

Reactive Cocoa Lightning Talk

  • 1.
    ReactiveCocoa Bob Spryn LoHi Labs @sprynmr(github, twitter) ! ! ! https://github.com/ReactiveCocoa/ReactiveCocoa
  • 2.
    ReactiveCocoa • An implementation offunctional reactive programming • It provides APIs for composing and transforming streams of values • “Signals” send you these values over time for you to react to http://en.wikipedia.org/wiki/Functional_reactive_programming
  • 3.
  • 4.
    Not just anotherAPI. It enables you to Program Smarter Focus on WHAT not HOW
  • 5.
  • 6.
    • Setup your reactions •Compose, Reactive!!! Declarative!!! split, filter, etc. What does that even mean?
  • 7.
    Imperative The way wenormally program.
  • 8.
    Imperative The way wenormally program. • Observe, wait, then command & control • Dealing with the HOW, not just the WHAT • Code for controlling flow is spread all over
  • 9.
    Auto-layout : ManagingFrames ReactiveCocoa : Imperative programming
  • 10.
  • 11.
    BOOL loadingNextPageOfComments; 2 states BOOLcommentsAreShowing; 4 states BOOL commentsLoadingShowing; 8 states BOOL flippingAnswers; 16 states BOOL isOwnerOfQuestion; 32 states
  • 12.
    - (void) updateChangeAnswerButtonText{ if (self.didAnswerQuestion && self.inResultsView) { [self.commentHeaderCell configureWithStyle:TCQuestionDetailCommentHeaderCellChangeAnswer]; } else if (self.isOwnerOfQuestion && !self.didAnswerQuestion && self.inResultsView) { [self.commentHeaderCell configureWithStyle:TCQuestionDetailCommentHeaderCellViewAnswers]; } else { [self.commentHeaderCell configureWithStyle:TCQuestionDetailCommentHeaderCellViewStats]; } } - (void) updateViewCommentStatus { if ((self.didAnswerQuestion || self.isOwnerOfQuestion) && !self.commentsAreShowing) { self.commentsAreShowing = YES; - (void) prepareForReuse { self.commentsLoadingShowing = YES; self.state = TCQuestionDetailViewContro … self.questionFullyLoaded = NO; } self.isOwnerOfQuestion = NO; self.didAnswerQuestion = NO; [self showCommentBox:self.inResultsView || self.isOwnerOfQuestion]; [self showCommentBox:NO]; } self.loadingNextPageOfComments = NO; self.commentsAreShowing = NO; self.commentsLoadingShowing = NO; ! ^aBlock { sself.didAnswerQuestion = sself.question.userResponse ? YES : NO; sself.inResultsView = sself.didAnswerQuestion || self.isOwnerOfQuestion; if (sself.questionFullyLoaded) { return; } … } } l co Rea rom ef d file one
  • 13.
    ReactiveCocoa to theRescue! • Signals instead of mutable variables • RACSignal – Think of it as a beacon sending out new values to it’s subscribers
  • 14.
    RACSignal • A unified interfacefor observing and reacting to all kinds of events and their values • UI Action • Async Network Call • KVO • Async Processing t’s I in ll a t! pu
  • 15.
    RACSignal • Shared vocabulary fortransforming the received values • • Combine, filter, reduce, map, and many more operations Eventually generate output (side effects) • Updating a label • Update an array with objects from the network • etc.
  • 16.
    - (void)viewDidLoad {
 [superviewDidLoad];
 [self.username
 addTarget:self
 action:@selector(textFieldTextDidChange:)
 forControlEvents:UIControlEventAllEditingEvents];
 [self.email
 addTarget:self
 action:@selector(textFieldTextDidChange:)
 forControlEvents:UIControlEventAllEditingEvents];
 Your name Your email address Sign Up abled ton.en ut gnUpB si } ! - (void)textFieldTextDidChange:(UITextField *)field {
 BOOL validUsername = self.username.text.length > 0;
 
 NSRange at = [self.email.text rangeOfString:@"@"];
 
 BOOL validEmail = at.location != NSNotFound;
 self.signupButton.enabled = validUsername &&
 validEmail;
 } Old Solved the imperative way.
  • 17.
    Your name Your emailaddress RAC(self.signUpButton, enabled) = [RACSignal combineLatest:@[
 self.name.rac_textSignal,
 self.email.rac_textSignal
 ]
 reduce:^(NSString *name, NSString *email) {
 NSRange at = [email rangeOfString:@"@"]; return @(at.location != NSNotFound && name.length > 0);
 }]; Sign Up ould I Sh SOME AWE bled? e ena b Solved the reactive way.
  • 18.
    Your name Your emailaddress RAC(self.signUpButton, enabled) = [RACSignal combineLatest:@[
 self.name.rac_textSignal,
 self.email.rac_textSignal
 ]
 reduce:^(NSString *name, NSString *email) {
 NSRange at = [email rangeOfString:@"@"]; return @(at.location != NSNotFound && name.length > 0);
 }]; Sign Up ould I Sh SOME AWE bled? e ena b Solved the reactive way.
  • 19.
    Network Validation? Easy. Your name Youremail address Sign Up RACSignal *validateEmailSignal = [self.email.rac_textSignal map:^id(NSString *emailString) { return [MyAPI validatedEmail:emailString]; }]; uld I Sho bled? be ena ! RAC(self.signUpButton, enabled) = [RACSignal combineLatest:@[
 self.name.rac_textSignal,
 validateEmailSignal
 ]
 reduce:^(NSString *name, APIResponse *response) {
 return @(response.json.isValid == YES && name.length > 0);
 }]; SOME AWE Solved the reactive way.
  • 20.
    Network Validation? Easy. Your name Youremail address Sign Up RACSignal *validateEmailSignal = map }]; ! uld I Sho The point is to Minimize State RAC combineLatest ] reduce }]; Solved the SOME AWE bled? be ena
  • 21.
    Network Validation? Easy. Your name Youremail address Sign Up RACSignal *validateEmailSignal = map }]; ! uld I Sho The point is to Minimize State RAC combineLatest ] reduce }]; Solved the SOME AWE bled? be ena
  • 22.
    Check out ReactiveCocoa YourBrain Will Thank You https://github.com/ReactiveCocoa/ReactiveCocoa Bob Spryn LoHi Labs @sprynmr (github, twitter) ! Thanks to @jspahrsummers, @joshaber, @AshFurrow, @robb, @andrewsardone and @erikprice (github usernames) for sharing their presentation slides and helping me learn ReactiveCocoa