reactive cocoa cocoaheadsbe_2014
DESCRIPTION
Presentation on ReactiveCocoa given at the CocoaHeadsBE presentation on March 12th 2014.TRANSCRIPT
![Page 1: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/1.jpg)
ReactiveCocoa
Werner Ramaekers Jan Sabbe
Cocoaheads BE 12/03/2014
![Page 2: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/2.jpg)
![Page 3: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/3.jpg)
![Page 4: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/4.jpg)
ReactiveCocoa (RAC) is an Objective-C framework for
Functional Reactive Programming.
It provides APIs for composing and transforming streams of
values.
![Page 5: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/5.jpg)
Whut ?
![Page 6: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/6.jpg)
Programming
PIN OUT
Take inputs Produce outputs
![Page 7: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/7.jpg)
Imperative programming•int x; int y = 1; int z = 2;
•x = y + z; //x == 3; y == 1; z == 2; !
PIN OUT
![Page 8: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/8.jpg)
Imperative programming•int x; int y = 1; int z = 2;
•x = y + z; //x == 3; y == 1; z == 2; !
PIN OUT
•y = 2;
•NSLog(@“%i”, x); //-> ‘3’ !
# Input changed but output did NOT because it was declared earlier….
![Page 9: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/9.jpg)
Imperative programming•int x; int y = 1; int z = 2;
•x = y + z; //x == 3; y == 1; z == 2; !
PIN OUT
STATE •y = 2;
•NSLog(@“%i”, x); //-> ‘3’ !
# Input changed but output did NOT because it was declared earlier….
![Page 10: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/10.jpg)
Declaractive programming
•The developer describes the problem domain in a declarative way, !
•The focus is NOT on state !
•Focus is on : •data flow
•propagation of change
![Page 11: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/11.jpg)
Functional Programming
•is one way of declarative programming. !
•Functional programming..
•deemphasizes state & mutable data •emphasizes functions that produce
outputs based on inputs : z = f(x, y)
PIN OUT
![Page 12: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/12.jpg)
Reactive Programming
•also is a way of declarative programming !
•Reactive Programming .. •dynamically links the program’s behaviour
to its continuously updating data stream
PIN OUT
![Page 13: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/13.jpg)
Reactive Programming
•also is a way of declarative programming !
•Reactive Programming .. •dynamically links the program’s behaviour
to its continuously updating data stream
PIN OUT
•E.g. : a spreadsheet application where
•cell A1 (= B1 + C1)
![Page 14: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/14.jpg)
Functional Reactive Programming
•.. combines the FUNCTIONAL and REACTIVE programming styles. !
•.. links functions that observe continuous and dynamic streams of data (inputs) to the program’s behaviour (outputs) in real time.
![Page 15: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/15.jpg)
ReactiveCocoa (RAC) is an Objective-C framework for
Functional Reactive Programming.
It provides APIs for composing and transforming streams of
values.
![Page 16: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/16.jpg)
RAC : ReActiveCocoa
Stream Subscriber
RACStream produces a Stream existing of …
![Page 17: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/17.jpg)
RAC : ReActiveCocoa
Stream
Next Event
Subscriber
RACStream produces a Stream existing of …
![Page 18: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/18.jpg)
RAC : ReActiveCocoa
Stream
Next Event
Complete Event
Subscriber
RACStream produces a Stream existing of …
![Page 19: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/19.jpg)
RAC : ReActiveCocoa
Stream
Next Event
Complete Event
Subscriber
Error Event
RACStream produces a Stream existing of …
![Page 20: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/20.jpg)
RAC : ReActiveCocoa
Stream Subscriber
[ 1, 2, 3]
RACSequence
![Page 21: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/21.jpg)
RAC : ReActiveCocoa
Stream Subscriber
[ 1, 2, 3]
123
RACSequence
![Page 22: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/22.jpg)
RAC : ReActiveCocoa
Stream Subscriber
RACSignal
Client Server
![Page 23: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/23.jpg)
RAC : ReActiveCocoa
Stream Subscriber…
JSON
RACSignal
Client Server
![Page 24: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/24.jpg)
RAC : ReActiveCocoa
Stream Subscriber…
∞
RACSignal
Client
listen
![Page 25: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/25.jpg)
RAC : ReActiveCocoa
RACStream
RACSignal RACSequence
![Page 26: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/26.jpg)
ReactiveCocoa •RACStream
•abstract class
•represents some sequential flow of data
•RACSignal (cold)
•push-driven data stream of future values
•cfr Network call
•must be subscribed to in order to access data
•RACSequence
•pull-driven data stream
•similar to Cocoa collection classes (NSArray, ..)
•but values are evaluated lazily - only when needed
![Page 27: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/27.jpg)
Details please
![Page 28: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/28.jpg)
RACSignal!
[self.textField.rac_textSignal subscribeNext:^(id x) {
NSLog(@“New value : %@“, x);
} error:^(NSError *error){
NSLog(@“Error : %@“, error);
} completed:^{
NSLog(@“That’s all folks !”);
}];
![Page 29: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/29.jpg)
RACSignal!
[self.textField.rac_textSignal subscribeNext:^(id x) {
NSLog(@“New value : %@“, x);
!
!
!
!
}];
![Page 30: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/30.jpg)
RACSignal : combineLatest
123
C.L.
( )=,
![Page 31: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/31.jpg)
RACStream operators•Simplifies transformations of streams into
new streams
•map, filter, fold/reduce
!
![Page 32: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/32.jpg)
RACStream : map
MAP =
( ) =
RACSequence *stream = [@[@(1), @(2), @(3)] rac_sequence];
[stream map:^id(id value) {
return @(pow([value integerValue], 2));
}];
NSLog(@“%@“, [stream array]);
![Page 33: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/33.jpg)
RACStream : flatten map
FMAP =
( ) =
Function result = stream
![Page 34: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/34.jpg)
RACStream : filter
RACSequence *stream = [@[@(1), @(2), @(3)]; rac_sequence];
NSLog(@“%@“,
[[[array rac_sequence] filter:^BOOL(id value){
return [value integerValue] % 2 == 0;
}] array]
);
Filter =
( ) = True?
![Page 35: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/35.jpg)
![Page 36: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/36.jpg)
Validating input the “old” way
#pragma mark - UITextFieldDelegate !- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { self.createButton.enabled = [self isFormValid]; ! return YES; }
![Page 37: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/37.jpg)
Validating input the “old” way
#pragma mark - UITextFieldDelegate !- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { self.createButton.enabled = [self isFormValid]; ! return YES; }
- (BOOL)isFormValid { return [self.usernameField.text length] > 0 && [self.emailField.text length] > 0 && [self.passwordField.text length] > 0 && [self.passwordField.text isEqual:self.passwordVerificationField.text]; } … …… …
![Page 38: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/38.jpg)
![Page 39: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/39.jpg)
Validating input the “RAC” wayRAC(self.createButton, enabled) = ! [RACSignal combineLatest:@[ self.usernameTF.rac_textSignal, self.emailFieldTF.rac_textSignal, self.passwordFieldTF.rac_textSignal, self.passwordVerificationFieldTF.rac_textSignal ] reduce:^(NSString *username, NSString *email, NSString *password, NSString *passwordVerification) { return @([username length] > 0 && [email length] > 0 && [password length] > 8 && [password isEqual:passwordVerification]); }];
![Page 40: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/40.jpg)
Validating input the “RAC” wayRAC(self.createButton, enabled) = ! [RACSignal combineLatest:@[ self.usernameTF.rac_textSignal, self.emailFieldTF.rac_textSignal, self.passwordFieldTF.rac_textSignal, self.passwordVerificationFieldTF.rac_textSignal ] reduce:^(NSString *username, NSString *email, NSString *password, NSString *passwordVerification) { return @([username length] > 0 && [email length] > 0 && [password length] > 8 && [password isEqual:passwordVerification]); }];
![Page 41: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/41.jpg)
“not so fast cowboy .. “•RAC(object, key path) is a macro
•creates a one-way binding
•ex. bind “enabled” property of a UIButton to a signal
![Page 42: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/42.jpg)
Now, show me a real app
![Page 43: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/43.jpg)
Station locator app
![Page 44: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/44.jpg)
Station locator app
![Page 45: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/45.jpg)
Station locator app
![Page 46: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/46.jpg)
Station locator app
Core Data
Stations GPS coord Services Prices
![Page 47: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/47.jpg)
Station locator app
Core Data
Stations GPS coord Services Prices
Driving distance
![Page 48: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/48.jpg)
Station locator app
Prices.xml
Core Data
Stations GPS coord Services Prices
Driving distance
![Page 49: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/49.jpg)
Station locator app
Stations.xml Prices.xml
Core Data
Stations GPS coord Services Prices
Driving distance
![Page 50: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/50.jpg)
Easier asynchronous code
Driving distance
1
2
3 Core Data lookup in Background
current location
![Page 51: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/51.jpg)
RAC( ) = (51.2, 5.46)
station (id=4)
flattenMap searchClosest(51.2,5.46)
flattenMap getDrivingDistance(4)
JSON
map JSON -> km
"4.5 km"
![Page 52: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/52.jpg)
Sort stations by driving distance
station (id=1)
station (id=3)
station (id=2)
getDrivingDistance
combineLatest sort [3,1,2]
fetching driving distances concurrentlywhen all available, sort
![Page 53: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/53.jpg)
MVC
![Page 54: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/54.jpg)
MVC
![Page 55: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/55.jpg)
Scott, how do we test UIViewControllers
![Page 56: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/56.jpg)
ViewModel patternViewController sets up bindinganimations
ViewModel (BOOL) shop (BOOL) bread (RACCommand) search
SearchService (RACSignal) searchWithCriteria
validates + delegate to service
do actual search
![Page 57: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/57.jpg)
ViewModel patternViewController sets up bindinganimations
ViewModel (BOOL) shop (BOOL) bread (RACCommand) search
SearchService (RACSignal) searchWithCriteria
mock out the real search service
do search against in memory DB
easily testable
harder to test
hard to test but trivial
![Page 58: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/58.jpg)
ViewModel patternViewController sets up bindinganimations
ViewModel (BOOL) shop (BOOL) bread (RACCommand) search
SearchService (RACSignal) searchWithCriteria
validates + delegate to service
do actual search
what is this?
![Page 59: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/59.jpg)
RACCommand
while getting current location, searching stations, sort by driving distance,... show activity indicator
[[RACCommand alloc] initWithSignalBlock:^RACSignal *(id sender) { return [self createSearchSignal]; }];
ViewModel
![Page 60: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/60.jpg)
RACCommand
while getting current location, searching stations, sort by driving distance,... show activity indicator
[[RACCommand alloc] initWithSignalBlock:^RACSignal *(id sender) { return [self createSearchSignal]; }];
ViewModel
ViewControllerself.searchButton.rac_command = self.viewModel.searchCommand; RAC(self, spinner.hidden) = [self.viewModel.searchCommand.executing not];
![Page 61: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/61.jpg)
ReactiveCocoa …•keeps the app focused on representing data
& UX
•can reduce complexity bc you don’t need to worry about ‘state’ so much
•keeps related code close together (via blocks)
•helps to make your code more testable (via MVVM)
![Page 62: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/62.jpg)
but ReactiveCocoa …•introduces another way of thinking.
•adds another learning curve on top of Cocoa !
•is a framework by GitHub and not Apple !
•will Apple "sherlock" ReactiveCocoa ?
![Page 63: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/63.jpg)
One last thing
![Page 64: Reactive cocoa cocoaheadsbe_2014](https://reader033.vdocuments.net/reader033/viewer/2022052523/554faf4fb4c9057b298b4fd7/html5/thumbnails/64.jpg)
Thank you