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

ReactiveCocoa

 ReactiveCocoa

My talk for UIKonf 2013 about ReactiveCocoa and how to get rid of state

B00d4ed5d1e6cb9fc840167820247515?s=128

Robert Böhnke

May 02, 2013
Tweet

Transcript

  1. ReactiveCocoa OR: How I stopped worrying about state and love

    FRP
  2.  ✉   robb robb@robb.is tmp ceterum_censeo

  3. Let’s talk about State

  4. evil √

  5. Have you tried turning it off and on again?

  6. Have you tried turning it off and on again? Have

    you tried turning it off and on again?
  7. state

  8. @property (readwrite, …) BOOL quacksLikeADuck; @property (readwrite, …) BOOL walksLikeADuck;

    @property (readonly, …) BOOL probablyADuck;
  9. + (NSSet *)keyPathsForValuesAffectingProbablyADuck { return [NSSet setWithObjects:@”walksLikeADuck”, @”quacksLikeADuck”, nil]; }

    - (BOOL)isProbablyADuck { return _quacksLikeADuck && _walksLikeADuck; }
  10. ReactiveCocoa

  11. RAC(self.probablyADuck) = [RACSignal combineLatest:@[ RACAbleWithStart(self.walksLikeADuck), RACAbleWithStart(self.quacksLikeADuck) ] reduce:^(NSNumber *walks, NSNumber

    *quacks) { return @(walks.boolValue && quaks.boolValue); }];
  12. None
  13. [self.usernameField addTarget:self action:@selector(textFieldDidUpdate:) forControlEvents:UIControlEventEditingChanged]; [self.emailField addTarget:self action:@selector(textFieldDidUpdate:) forControlEvents:UIControlEventEditingChanged]; - (void)textFieldDidUpdate:(UITextField

    *)textField { BOOL validUsername = self.usernameField.text.length > 0; BOOL validEmail = [self.emailField.text uik_isEmail]; self.signupButton.enabled = validEmail && validUsername; }
  14. because programming

  15. [self.usernameField addTarget:self action:@selector(textFieldDidUpdate:) forControlEvents:UIControlEventEditingChanged]; [self.emailField addTarget:self action:@selector(textFieldDidUpdate:) forControlEvents:UIControlEventEditingChanged]; - (void)textFieldDidUpdate:(UITextField

    *)textField { BOOL validUsername = self.usernameField.text.length > 0; BOOL validEmail = [self.emailField.text uik_isEmail]; self.signupButton.enabled = validEmail && validUsername; }
  16. RAC(self.signupButton.enabled) = [RACSignal combineLatest:@[ self.usernameField.rac_textSignal, self.emailField.rac_textSignal ] reduce:^(NSString *username, NSString

    *email) { BOOL validUsername = username.length > 0; BOOL validEmail = [email uik_isEmail]; return @(validUsername && validEmail); }];
  17. FRP

  18. None
  19. None
  20. ReactiveCocoa

  21. @YES @NO @YES RACSignal

  22. <UIControlEventEditingChanged> RACSignal

  23. {“json_string”: “ohai”} RACSignal

  24. RACSignal - (void)sendNext:(id)value; - (void)sendCompleted; - (void)sendError:(NSError *)error;

  25. so, what?

  26. map, reduce, filter

  27. Let’s talk about Asynchrony

  28. None
  29. Blocks are awesome

  30. void (^cb)(id operation, id result); void (^cb)(id operation, NSError *error);

    void (^cb)(id result, NSError *error); void (^cb)(NSError *error, id result);
  31. [client logIn:^{ [client loadMeUser:^(UIKUser *user) { [client loadNewslettersForUser:user success:^(NSArray *result)

    NSLog(@"Your newsletters: %@", array); } failure:^(NSError *error) { // … }]; } failure:^(NSError *error) { // … }]; } failure:^(NSError *error) { // … }];
  32. RACSignal

  33. - (RACSignal *)logIn; - (RACSignal *)loadMeUser; - (RACSignal *)loadNewslettersForUser:(…)user;

  34. [[[[client logIn] sequenceNext:^{ return [client loadMeUser]; }] flattenMap:^(UIKUser *user) {

    return [client loadNewslettersForUser:user]; }] subscribeNext:^(NSArray *newsletters) { NSLog(@"Your newsletters: %@", newsletters); } error:^(NSError *error) { // … }];
  35. None
  36. - (RACSignal *)validateEmail:(NSString *)email;

  37. RACSignal *validEmail = [[self.emailField.rac_textSignal map:^(NSString *email) { return [[client validateEmail:email]

    startWith:@NO]; }] switchToLatest]; RACSignal *validForm = [RACSignal combineLatest:@[ validUsername, validEmail ] reduce:^(NSNumber *a, NSNumber *b) { return @(a.boolValue && b.boolValue); }]; RAC(self.signupButton.enabled) = validForm;
  38. None
  39. where's the catch?

  40. •conceptual overhead •debugging can get tricky (logAll is your friend)

    •forces you to think
  41. should I use it?

  42. Probably!

  43. state

  44. None