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

ReactiveCocoa

 ReactiveCocoa

Overview of ReactiveCocoa framework

Oleksandr Voronov

August 10, 2013
Tweet

More Decks by Oleksandr Voronov

Other Decks in Programming

Transcript

  1. Functional Reactive Programming (FRP) is a declarative programming paradigm for

    working with mutable time- varying values. Declarative – is about “what” not “how” to accomplish. Unlike imperative approach, system takes care of “how”. FRP
  2. What and How What and how NSArray *words = ...;

    for (NSUInteger index = 0; index < words.count; index++) { NSString *word = words[index]; // do stuff }
  3. What and How What and how NSArray *words = ...;

    for (NSUInteger index = 0; index < words.count; index++) { NSString *word = words[index]; // do stuff } What NSArray *words = ...; for (NSString *word in words) { // do stuff }
  4. What and How What and how NSMutableArray *uppercasedWords = [NSMutableArray

    array]; for (NSString *word in words) { [uppercasedWords addObject:word.uppercaseString]; }
  5. What and How What and how NSMutableArray *uppercasedWords = [NSMutableArray

    array]; for (NSString *word in words) { [uppercasedWords addObject:word.uppercaseString]; } What NSArray *uppercasedWords = [words map:^(NSString *word) { return word.uppercaseString; }];
  6. Key concepts Avoids state and mutable data Any computation is

    mathematical function Functional Programming
  7. State BOOL walksLikeADuck; // 2 states BOOL quacksLikeADuck; // 4

    states BOOL isProbablyADuck; // 8 states BOOL maybeItCanFly; // 16 states Complexity is STATE
  8. Minimize state by deriving it State BOOL walksLikeADuck; BOOL quacksLikeADuck;

    BOOL isProbablyADuck; BOOL walksLikeADuck; // 2 states BOOL quacksLikeADuck; // 4 states BOOL isProbablyADuck; // 4 states
  9. Functions Comparison Imperative function has side effects that can change

    program state behaves differently depending on program state
  10. Functions Comparison Imperative function has side effects that can change

    program state behaves differently depending on program state Mathematical function result of a function depends only on the arguments easier to understand and predict the behavior of a program
  11. Reactive programming – programming paradigm oriented around data flows and

    the propagation of changes. Reactive Programming Data flows can be either static or dynamic.
  12. Data Changes Propagation Imperative approach b = 10 c =

    11 a = b + c (21) b = 11 a = ? (21)
  13. Data Changes Propagation Imperative approach b = 10 c =

    11 a = b + c (21) b = 11 a = ? (21) Reactive approach b = 10 c = 11 a = b + c (21) b = 11 a = ? (22)
  14. Why not KVO? Key Value Observing – mechanism that allows

    objects to be notified of changes to specified properties of other objects.
  15. Why not KVO? Key Value Observing – mechanism that allows

    objects to be notified of changes to specified properties of other objects. not easy to use lots of unused parameters hard to maintain multithreading no block-based API
  16. Why not KVO? // Some controller or else [dog addObserver:me

    forKeyPath:@"hunger" options:NSKeyValueObservingOptionNew context:NULL]; // . . . [dog removeObserver:me forKeyPath:@"hunger"]; // Observer class of ‘me’ object - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { // . . . }
  17. Why not KVO? // Some controller or else [dog addObserver:me

    forKeyPath:@"hunger" options:NSKeyValueObservingOptionNew context:NULL]; // . . . [dog removeObserver:me forKeyPath:@"hunger"]; // Observer class of ‘me’ object - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { // . . . } should remember pointer to observer object should remember key path should care of removing observer should implement observeValueForKeyPath... method in observer lots of if else statements because of keyPath
  18. Why not KVO? Unlike KVO, in ReactiveCocoa and FRP in

    general you also can: combine operations together or derive state react on UI controls events and everything that changes over time operate with timers easily maintain networking operations operations can be chained sequently instead of nesting blocks
  19. Bindings Developing for Mac OS X reveals Bindings. allow programming

    in IB replace boilerplate glue code This is real magic but . . . : no support for iOS development quite limited cannot be debugged
  20. Signals Signal – is a time varying value int a

    = 0 a = 1 a = 2 . . . a = n 1 2 n .
  21. Events Signals send three different types of events to their

    subscribers: next – provides a new value from the stream.
  22. Events Signals send three different types of events to their

    subscribers: next – provides a new value from the stream. error – indicates that an error occurred before the signal could finish.
  23. Events Signals send three different types of events to their

    subscribers: next – provides a new value from the stream. error – indicates that an error occurred before the signal could finish. completed – indicates that the signal finished successfully, and that no more values will be added to the stream.
  24. ReactiveCocoa Basics Stream Sequence Signal Stream (RACStream)– abstract representation of

    series of values. Streams are Haskell monads. Signal (RACSignal) – push-driven stream, represents data that will be delivered in the future. Sequence (RACSequence) – pull-driven stream that behaves more like a collection (NSArray, etc)
  25. RAC(self.btnLogin, enabled) = [RACSignal combineLatest:@[ self.tfUsername.rac_textSignal, self.tfPassword.rac_textSignal ] reduce:^id(RACTuple *fields)

    { NSString *username = fields.first; NSString *password = fields.second; return @(username.length > 0 && password.length > 0); }]; Combining and reducing Signals
  26. RAC(self.btnLogin, enabled) = [RACSignal combineLatest:@[ self.tfUsername.rac_textSignal, self.tfPassword.rac_textSignal ] reduce:^id(RACTuple *fields)

    { NSString *username = fields.first; NSString *password = fields.second; return @(username.length > 0 && password.length > 0); }]; Combining and reducing Signals combineLate st: reduce: Bind rac_textSign al rac_textSign al
  27. RAC(self.lblTimeStamp, text) = [[[[RACSignal interval:1] startWith:[NSDate date]] map:^id(NSDate *value) {

    NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:(NSMinuteCalendarUnit| NSSecondCalendarUnit) fromDate:value]; return [NSString stringWithFormat:@"%d:%02d", dateComponents.minute, dateComponents.second]; }] deliverOn:[RACScheduler mainThreadScheduler] ]; Working With Timers  And Schedulers
  28. Non-FRP Approach [client logInWithSuccess:^{ [client loadCachedMessagesWithSuccess:^(NSArray *messages) { [client fetchMessagesAfterMessage:messages.lastObject

    success:^(NSArray *nextMsgs) { NSLog(@"Fetched all messages."); } failure:^(NSError *error) { [self presentError:error]; }]; } failure:^(NSError *error) { [self presentError:error]; }]; } failure:^(NSError *error) { [self presentError:error]; }]; Reducing chains of callbacks
  29. Non-FRP Approach [client logInWithSuccess:^{ [client loadCachedMessagesWithSuccess:^(NSArray *messages) { [client fetchMessagesAfterMessage:messages.lastObject

    success:^(NSArray *nextMsgs) { NSLog(@"Fetched all messages."); } failure:^(NSError *error) { [self presentError:error]; }]; } failure:^(NSError *error) { [self presentError:error]; }]; } failure:^(NSError *error) { [self presentError:error]; }]; Reducing chains of callbacks Using ReactiveCocoa [[[[client logIn] sequenceNext:^{ return [client loadCachedMessages]; }] flattenMap:^(NSArray *messages) { return [client fetchMessagesAfterMessage: messages.lastObject]; }] subscribeError:^(NSError *error) { [self presentError:error]; } completed:^{ NSLog(@"Fetched all messages."); }];
  30. Using switchToLatest RACSubject *letters = [RACSubject subject]; RACSubject *numbers =

    [RACSubject subject]; RACSubject *signalOfSignals = [RACSubject subject]; RACSignal *switched = [signalOfSignals switchToLatest]; // Outputs: A B 1 D [switched subscribeNext:^(NSString *x) { NSLog(@"%@", x); }]; [signalOfSignals sendNext:letters]; [letters sendNext:@"A"]; [letters sendNext:@"B"]; [signalOfSignals sendNext:numbers]; [letters sendNext:@"C"]; [numbers sendNext:@"1"]; [signalOfSignals sendNext:letters]; [numbers sendNext:@"2"]; [letters sendNext:@"D"];
  31. Where next? You can find full documentation on GitHub repo

    of this project: http:/ /github.com/ReactiveCocoa/ ReactiveCocoa Should take a look at Elm and meet some FRP theory
 http:/ /elm-lang.org/ Lookup brief material on Wikipedia or some blogs
  32. What else? FRP-based languages and frameworks: Elm ClojureScript C# –

    Rx JavaScript – Flapjax, RxJS, Bacon.js, Java – RxJava Ruby – Frapuccino