Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduction to Functional Reactive Programming with ReactiveCocoa

CocoaHeadsNL
April 21, 2015
200

Introduction to Functional Reactive Programming with ReactiveCocoa

Presentation given by Ian Dundas at the CocoaHeadsNL meetup in April 2015.
Full material is here: https://github.com/iandundas/reactivecocoa-presentation
Video of the talk is here: https://www.youtube.com/watch?v=vKAWrSX-3BU

CocoaHeadsNL

April 21, 2015
Tweet

Transcript

  1. Coming up.. • Problems of imperative programming • How Functional

    Reactive programming addresses these issues • ReactiveCocoa, an implementation of FRP
  2. [self.overlayYAxisLayoutConstraint setConstant:200];
 [self.tapGestureRecogniser setEnabled:NO]; BOOL isSyncing= NO; 
 BOOL overlayIsShowing=

    YES;
 BOOL userIsActive=YES;
 
 x= 1 y= 2
 z= x + y; # z is 3
 y= 4; #change value of y 
 print z: "3" # z is still 3
  3. –Justin Spahr-Summers, co-author, on NSBrief podcast "ReactiveCocoa comes from the

    world of Functional Reactive Programming, which is kinda like a paradigm shift on top of a paradigm shift: it’s Functional Programming with Reactive Programming added on top, which makes it intimidating because it’s a big change from what we’re used to"
  4. Functional Programming - from 1000 miles high • Distilled down

    to an “abhorrence of state” • Functions don’t have side-effects • Immutability • Side-effects are useful, however
  5. Reactive Programming x= 1 y= 2
 z= x + y

    # z is 3
 y= 4 # change value of y 
 print z: “5” # z was updated z “reacts” to the changes of x and y
  6. Functional Reactive Programming • Just a combination of functional and

    reactive paradigms • “We model user input as a function that changes over time, abstracting away the idea of mutable state.” • Can now model difficult things like *user input*
  7. Signals & Subscriptions • Signal can send: • “Next”, one

    or many times • “Completed”, or “Error”, only once • We can subscribe to receive these values from a Signal, -> we become a Subscriber.
  8. So - what is ReactiveCocoa? • ReactiveCocoa (RAC) is an

    open source library that brings Functional Reactive Programming paradigm to Objective-C. • It was created by Josh Abernathy & Justin Spahr- Summers in the development of GitHub for Mac.
  9. Signal Operators: Map: [[RACObserve(self, isLoggedIn) 
 map:^id(NSNumber *boolValue){
 BOOL enabled=

    [boolValue boolValue];
 return enabled? @"Logged in": @"Logged out";
 }] 
 subscribeNext:^(NSString *loggedInString){
 NSLog(@"We are currently %@", loggedInString);
 // output: "We are currently: Logged in” [self.tableView reloadData]; // side-effect
 }]; @property(nonatomic) BOOL *isLoggedIn;
  10. Signal Operators: Filter: [[RACObserve(self, username)
 filter:^(NSString *newName) {
 return newName.length

    > 4;
 }]
 subscribeNext:^(NSString *newName) {
 NSLog(@"%@", newName);
 }];
 @property (nonatomic, copy) NSString *username;
  11. Binding with RAC() RAC(self.firstNameLabel, text) = RACObserve(self, firstName); binds self.firstNameLabel’s

    text property to the signal produces a signal which sends a new value each time self.firstName changes
  12. ! Powerful Binding ! & example of combineLatest:reduce: RACSignal *loginShouldBeEnabledSignal

    = [RACSignal 
 combineLatest:@[
 self.usernameTextField.rac_textSignal, 
 self.passwordTextField.rac_textSignal,
 RACObserve(LoginManager.sharedManager, loggingIn)
 ] 
 reduce: (id) ^(NSString *username, NSString *password, NSNumber *loggingIn) {
 BOOL shouldBeEnabled= 
 (username.length > 0 && password.length > 0 && !loggingIn.boolValue);
 
 return @(shouldBeEnabled);
 }
 ];
 // Bind signal to `enabled` property on loginButton
 RAC(self.loginButton, enabled) = loginShouldBeEnabledSignal;
  13. –ReactiveCocoa README.md “By chaining, combining, and reacting to signals, software

    can be written declaratively, without the need for code that continually observes and updates values (manually).”
  14. Derived State • A core concept in Functional Reactive Programming

    • State is OK in ReactiveCocoa, as long as its bound to a signal • You never explicitly set the value of a bound property, but rather rely on signal transformations to derive that state for you. http://reactivecocoa.io/philosophy.html
  15. Getting started: 
 Replace your KVO with RAC @implementation IDViewController


    
 -(void)dealloc{
 [self teardownObservers];
 }
 
 -(void)viewDidLoad {
 [super viewDidLoad];
 [self setupObservers];
 }
 
 -(void)setupObservers{
 [self.viewModel addObserver:self
 forKeyPath:@"firstName"
 options:NSKeyValueObservingOptionNew context:NULL
 ];
 }
 
 -(void)teardownObservers{
 [self.viewModel removeObserver:self forKeyPath:@"firstName"];
 }
 
 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
 change:(NSDictionary *)change context:(void *)context{
 
 if ([keyPath isEqualToString:@"firstName"]){
 NSLog(@"firstName did change");
 }
 }
 @end
  16. Getting started: 
 Replace your KVO with RAC @implementation IDViewController


    
 -(void)viewDidLoad {
 [super viewDidLoad];
 
 [RACObserve(self, firstName) subscribeNext:^(id x) {
 NSLog(@"firstName did change");
 }];
 }
 
 @end
  17. [[[[[[[[self requestAccessToTwitterSignal]
 then:^RACSignal * {
 return self.searchTextField.rac_textSignal;
 }]
 filter:^BOOL (NSString

    *text) {
 return [self isValidSearchText:text];
 }] 
 http://www.raywenderlich.com/62796/reactivecocoa-tutorial-pt2
  18. [[[[[[[[self requestAccessToTwitterSignal]
 then:^RACSignal * {
 return self.searchTextField.rac_textSignal;
 }]
 filter:^BOOL (NSString

    *text) {
 return [self isValidSearchText:text];
 }]
 throttle:0.5] http://www.raywenderlich.com/62796/reactivecocoa-tutorial-pt2
  19. [[[[[[[[self requestAccessToTwitterSignal]
 then:^RACSignal * {
 return self.searchTextField.rac_textSignal;
 }]
 filter:^BOOL (NSString

    *text) {
 return [self isValidSearchText:text];
 }]
 throttle:0.5]
 flattenMap:^RACStream * (NSString *text) {
 return [self signalForSearchWithText:text];
 }]
 http://www.raywenderlich.com/62796/reactivecocoa-tutorial-pt2
  20. [[[[[[[[self requestAccessToTwitterSignal]
 then:^RACSignal * {
 return self.searchTextField.rac_textSignal;
 }]
 filter:^BOOL (NSString

    *text) {
 return [self isValidSearchText:text];
 }]
 throttle:0.5]
 flattenMap:^RACStream * (NSString *text) {
 return [self signalForSearchWithText:text];
 }]
 map:^id (NSDictionary *jsonSearchResult) {
 NSArray *statuses = jsonSearchResult[@"statuses"];
 return statuses;
 }]
 http://www.raywenderlich.com/62796/reactivecocoa-tutorial-pt2
  21. [[[[[[[[self requestAccessToTwitterSignal]
 then:^RACSignal * {
 return self.searchTextField.rac_textSignal;
 }]
 filter:^BOOL (NSString

    *text) {
 return [self isValidSearchText:text];
 }]
 throttle:0.5]
 flattenMap:^RACStream * (NSString *text) {
 return [self signalForSearchWithText:text];
 }]
 map:^id (NSDictionary *jsonSearchResult) {
 NSArray *statuses = jsonSearchResult[@"statuses"];
 return statuses;
 }]
 deliverOn:[RACScheduler mainThreadScheduler]]
 http://www.raywenderlich.com/62796/reactivecocoa-tutorial-pt2
  22. [[[[[[[[self requestAccessToTwitterSignal]
 then:^RACSignal * {
 return self.searchTextField.rac_textSignal;
 }]
 filter:^BOOL (NSString

    *text) {
 return [self isValidSearchText:text];
 }]
 throttle:0.5]
 flattenMap:^RACStream * (NSString *text) {
 return [self signalForSearchWithText:text];
 }]
 map:^id (NSDictionary *jsonSearchResult) {
 NSArray *statuses = jsonSearchResult[@"statuses"];
 return statuses;
 }]
 deliverOn:[RACScheduler mainThreadScheduler]]
 subscribeNext:^(NSArray *tweets) {
 [self displayTweets:tweets];
 } error:^(NSError *error) {
 NSLog(@"An error occurred: %@", error);
 }]; http://www.raywenderlich.com/62796/reactivecocoa-tutorial-pt2
  23. –Evan Coleman, http://is.gd/kTQhF2 “At first, none of it made any

    sense to me. I spent the next week pouring over the ReactiveCocoa docs, but no matter how much I read, signals, etc .. they were all just words to me...It wasn’t until I dove head first into the code that I started to see the light."