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

ReactiveCocoa NSSpain

Robert Böhnke
September 18, 2013

ReactiveCocoa NSSpain

My talk for NSSpain 2013 on ReactiveCocoa

Robert Böhnke

September 18, 2013
Tweet

More Decks by Robert Böhnke

Other Decks in Programming

Transcript

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

    you tried turning it off and on again?
  2. - (void)setWalks:(BOOL)walks { _walks = walks; self.duck = walks &&

    self.quacks; } - (void)setQuacks:(BOOL)quacks { _quacks = quacks; self.duck = quacks && self.walks; }
  3. - (void)setWalks:(BOOL)walks { _walks = walks; self.duck = walks &&

    self.quacks; } - (void)setQuacks:(BOOL)quacks { _quacks = quacks; self.duck = quacks && self.walks; }
  4. RAC(self, duck) = [RACSignal combineLatest:@[ RACObserve(self, walks), RACObserve(self, quacks) ]

    reduce:^(NSNumber *walks, NSNumber *quacks) { return @(walks.boolValue && quacks.boolValue); }]:
  5. RAC(self, duck) = [RACSignal combineLatest:@[ RACObserve(self, walks), RACObserve(self, quacks) ]

    reduce:^(NSNumber *walks, NSNumber *quacks) { return @(walks.boolValue && quacks.boolValue); }]:
  6. RAC(self, duck) = [RACSignal combineLatest:@[ RACObserve(self, walks), RACObserve(self, quacks) ]

    reduce:^(NSNumber *walks, NSNumber *quacks) { return @(walks.boolValue && quacks.boolValue); }]:
  7. RAC(self, duck) = [RACSignal combineLatest:@[ RACObserve(self, walks), RACObserve(self, quacks) ]

    reduce:^(NSNumber *walks, NSNumber *quacks) { return @(walks.boolValue && quacks.boolValue); }]:
  8. RAC(self, duck) = [RACSignal combineLatest:@[ RACObserve(self, walks), RACObserve(self, quacks) ]

    reduce:^(NSNumber *walks, NSNumber *quacks) { return @(walks.boolValue && quacks.boolValue); }]:
  9. // and it even does KVO! RAC(self, duck) = [RACSignal

    combineLatest:@[ RACObserve(self, walks), RACObserve(self, quacks) ] reduce:^(NSNumber *walks, NSNumber *quacks) { return @(walks.boolValue && quacks.boolValue); }]:
  10. map

  11. - (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; }
  12. - (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; }
  13. 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); }]:
  14. 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); }]:
  15. 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); }]:
  16. 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); }]:
  17. [client logInWithSuccess:^{ [client loadMeUserWithSuccess:^(SPUser *me) { [client loadFilesForUser:me withSuccess:^(NSArray *files)

    { NSLog(@"Help me, " "I'm trapped in callback hell!"); } error:^(NSError *error) { // Handle failure } } error:^(NSError *error) { // Handle failure }]; } error:^(NSError *error) { // Handle failure }]; omg, why?!
  18. [self enqueueHTTPRequestOperation:operation]; - (RACSignal *)enqueueRequest:(NSURLRequest *)req { return [RACSignal createSignal:^(id<RACSubscriber>

    subscriber) { AFHTTPRequestOperation *operation; operation = [self HTTPRequestOperationWithRequest:req success:^(id operation, id response) { [subscriber sendNext:response]; [subscriber sendCompleted]; } failure:^(id operation, NSError *error) { [subscriber sendError:error]; }];
  19. [self enqueueHTTPRequestOperation:operation]; - (RACSignal *)enqueueRequest:(NSURLRequest *)req { return [RACSignal createSignal:^(id<RACSubscriber>

    subscriber) { AFHTTPRequestOperation *operation; operation = [self HTTPRequestOperationWithRequest:req success:^(id operation, id response) { [subscriber sendNext:response]; [subscriber sendCompleted]; } failure:^(id operation, NSError *error) { [subscriber sendError:error]; }];
  20. - (RACSignal *)enqueueRequest:(NSURLRequest *)req { return [RACSignal createSignal:^(id<RACSubscriber> subscriber) {

    AFHTTPRequestOperation *operation; operation = [self HTTPRequestOperationWithRequest:req success:^(id operation, id response) { [subscriber sendNext:response]; [subscriber sendCompleted]; } failure:^(id operation, NSError *error) { [subscriber sendError:error]; }]; [self enqueueHTTPRequestOperation:operation];
  21. - (RACSignal *)enqueueRequest:(NSURLRequest *)req { return [RACSignal createSignal:^(id<RACSubscriber> subscriber) {

    AFHTTPRequestOperation *operation; operation = [self HTTPRequestOperationWithRequest:req success:^(id operation, id response) { [subscriber sendNext:response]; [subscriber sendCompleted]; } failure:^(id operation, NSError *error) { [subscriber sendError:error]; }]; [self enqueueHTTPRequestOperation:operation];
  22. - (RACSignal *)enqueueRequest:(NSURLRequest *)req { return [RACSignal createSignal:^(id<RACSubscriber> subscriber) {

    AFHTTPRequestOperation *operation; operation = [self HTTPRequestOperationWithRequest:req success:^(id operation, id response) { [subscriber sendNext:response]; [subscriber sendCompleted]; } failure:^(id operation, NSError *error) { [subscriber sendError:error]; }]; [self enqueueHTTPRequestOperation:operation];
  23. [self enqueueHTTPRequestOperation:operation]; return [RACDisposable disposableWithBlock:^{ [operation cancel]; }]; }]; createSignal:^(id<RACSubscriber>

    subscriber) { AFHTTPRequestOperation *operation; operation = [self HTTPRequestOperationWithRequest:req success:^(id operation, id response) { [subscriber sendNext:response]; [subscriber sendCompleted]; } failure:^(id operation, NSError *error) { [subscriber sendError:error]; }];
  24. [self enqueueHTTPRequestOperation:operation]; return [RACDisposable disposableWithBlock:^{ [operation cancel]; }]; }]; createSignal:^(id<RACSubscriber>

    subscriber) { AFHTTPRequestOperation *operation; operation = [self HTTPRequestOperationWithRequest:req success:^(id operation, id response) { [subscriber sendNext:response]; [subscriber sendCompleted]; } failure:^(id operation, NSError *error) { [subscriber sendError:error]; }];
  25. - (RACSignal *)fetchMeUser return [[self.client getPath:@"/me"] flattenMap:^(id JSON) { NSError

    *error; SPUser *user = [SPUser userWithJSON:JSON error:&error]; if (user == nil) { return [RACSignal error:error]; } else { return [RACSignal return:user]; } }]; }
  26. - (RACSignal *)fetchMeUser return [[self.client getPath:@"/me"] flattenMap:^(id JSON) { NSError

    *error; SPUser *user = [SPUser userWithJSON:JSON error:&error]; if (user == nil) { return [RACSignal error:error]; } else { return [RACSignal return:user]; } }]; }
  27. - (RACSignal *)fetchMeUser return [[self.client getPath:@"/me"] flattenMap:^(id JSON) { NSError

    *error; SPUser *user = [SPUser userWithJSON:JSON error:&error]; if (user == nil) { return [RACSignal error:error]; } else { return [RACSignal return:user]; } }]; }
  28. - (RACSignal *)fetchMeUser return [[self.client getPath:@"/me"] flattenMap:^(id JSON) { NSError

    *error; SPUser *user = [SPUser userWithJSON:JSON error:&error]; if (user == nil) { return [RACSignal error:error]; } else { return [RACSignal return:user]; } }]; }
  29. - (RACSignal *)fetchMeUser return [[self.client getPath:@"/me"] flattenMap:^(id JSON) { NSError

    *error; SPUser *user = [SPUser userWithJSON:JSON error:&error]; if (user == nil) { return [RACSignal error:error]; } else { return [RACSignal return:user]; } }]; } check out Mantle!
  30. - (RACSignal *)fetchMeUser return [[self.client getPath:@"/me"] flattenMap:^(id JSON) { NSError

    *error; SPUser *user = [SPUser userWithJSON:JSON error:&error]; if (user == nil) { return [RACSignal error:error]; } else { return [RACSignal return:user]; } }]; }
  31. - (RACSignal *)fetchMeUser return [[self.client getPath:@"/me"] flattenMap:^(id JSON) { NSError

    *error; SPUser *user = [SPUser userWithJSON:JSON error:&error]; if (user == nil) { return [RACSignal error:error]; } else { return [RACSignal return:user]; } }]; }
  32. [[[[client logIn] then:^{ return [client fetchMeUser]; }] flattenMap:^(SPUser *me) {

    return [client fetchFilesForUser:me]; }] subscribeNext:^(NSArray *files) { NSLog(@"Files: %@", files); } error:^(NSError *error) { // Handle error }];
  33. [[[[client logIn] then:^{ return [client fetchMeUser]; }] flattenMap:^(SPUser *me) {

    return [client fetchFilesForUser:me]; }] subscribeNext:^(NSArray *files) { NSLog(@"Files: %@", files); } error:^(NSError *error) { // Handle error }];
  34. [[[[client logIn] then:^{ return [client fetchMeUser]; }] flattenMap:^(SPUser *me) {

    return [client fetchFilesForUser:me]; }] subscribeNext:^(NSArray *files) { NSLog(@"Files: %@", files); } error:^(NSError *error) { // Handle error }];
  35. [[[[client logIn] then:^{ return [client fetchMeUser]; }] flattenMap:^(SPUser *me) {

    return [client fetchFilesForUser:me]; }] subscribeNext:^(NSArray *files) { NSLog(@"Files: %@", files); } error:^(NSError *error) { // Handle error }];
  36. [[[[client logIn] then:^{ return [client fetchMeUser]; }] flattenMap:^(SPUser *me) {

    return [client fetchFilesForUser:me]; }] subscribeNext:^(NSArray *files) { NSLog(@"Files: %@", files); } error:^(NSError *error) { // Handle error }];
  37. [[[[client logIn] then:^{ return [client fetchMeUser]; }] flattenMap:^(SPUser *me) {

    return [client fetchFilesForUser:me]; }] subscribeNext:^(NSArray *files) { NSLog(@"Files: %@", files); } error:^(NSError *error) { // Handle error }];
  38. [[[[client logIn] then:^{ return [client fetchMeUser]; }] flattenMap:^(SPUser *me) {

    return [client fetchFilesForUser:me]; }] subscribeNext:^(NSArray *files) { NSLog(@"Files: %@", files); } error:^(NSError *error) { // Handle error }];
  39. self.name.rac_textSignal self.email.rac_textSignal reduce:^(NSString *name, NSString *email) { NSRange at =

    [email rangeOfString:@"@"]; return @(at.location != NSNotFound && name.length > 0); }]; RAC(self.signUpButton, enabled) = [RACSignal combineLatest:@[ ]
  40. self.name.rac_textSignal self.email.rac_textSignal reduce:^(NSString *name, NSString *email) { NSRange at =

    [email rangeOfString:@"@"]; return @(at.location != NSNotFound && name.length > 0); }]; RAC(self.signUpButton, enabled) = [RACSignal combineLatest:@[ ]
  41. validName, validEmail reduce:^(NSString *name, NSString *email) { NSRange at =

    [email rangeOfString:@"@"]; return @(at.location != NSNotFound && name.length > 0); }]; reduce:^(NSString *name, NSString *email) { NSRange at = [email rangeOfString:@"@"]; return @(at.location != NSNotFound && name.length > 0); }]; RAC(self.signUpButton, enabled) = [RACSignal combineLatest:@[ ]
  42. reduce:^(NSString *name, NSString *email) { NSRange at = [email rangeOfString:@"@"];

    return @(at.location != NSNotFound && name.length > 0); }]; validName, validEmail RAC(self.signUpButton, enabled) = [RACSignal combineLatest:@[ ]
  43. reduce:^(NSNumber *name, NSNumber *email) { return @(name.boolValue && email.boolValue); }];

    validName, validEmail map:^(NSString *name) { return @(name.length > 0); }]; RAC(self.signUpButton, enabled) = [RACSignal combineLatest:@[ ]
  44. RACSignal *validName = [self.name.rac_textSignal map:^(NSString *name) { return @(name.length >

    0); }]; reduce:^(NSNumber *name, NSNumber *email) { validName, validEmail RAC(self.signUpButton, enabled) = [RACSignal combineLatest:@[ ] RACSignal *validEmail = [[self.email.rac_textSignal map:^(NSString *email) { return [[client validateEmail:email] startWith:@NO]; }] switchToLatest];
  45. RACSignal *validName = [self.name.rac_textSignal map:^(NSString *name) { return @(name.length >

    0); }]; RACSignal *validEmail = [[self.email.rac_textSignal map:^(NSString *email) { return [[client validateEmail:email] startWith:@NO]; }] switchToLatest];
  46. RACSignal *validEmail = [[self.email.rac_textSignal map:^(NSString *email) { return [[client validateEmail:email]

    startWith:@NO]; }] switchToLatest]; RACSignal *validName = [self.name.rac_textSignal map:^(NSString *name) { return @(name.length > 0); }];
  47. RACSignal *validEmail = [[self.email.rac_textSignal map:^(NSString *email) { return [[client validateEmail:email]

    startWith:@NO]; }] switchToLatest]; RACSignal *validName = [self.name.rac_textSignal map:^(NSString *name) { return @(name.length > 0); }];
  48. Recap + Declarative code + Easy handling of asynchronous tasks

    + Great Composition − Conceptual overhead
  49. Recap + Declarative code + Easy handling of asynchronous tasks

    + Great Composition − Conceptual overhead − Debugging can get tricky
  50. Recap (dtrace support coming soon) + Declarative code + Easy

    handling of asynchronous tasks + Great Composition − Conceptual overhead − Debugging can get tricky
  51. Qs?

  52. iPhone 5 Setch Template courtesy of Denis Rojčyk Cloud icon

    curtesy of Dmitry Baranovskiy, from The Noun Project