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

ReactiveCocoa

 ReactiveCocoa

Overview of ReactiveCocoa framework

D94c9a683d3b45cfe42548cd5a1a39b0?s=128

Alexander Voronov

August 10, 2013
Tweet

Transcript

  1. Alexander Voronov @aleks_voronov (Welcome!)

  2. Reactive Cocoa http:/ /github.com/ReactiveCocoa/ReactiveCocoa

  3. C# Reactive extensions (Rx) Clojure Elm Inspired By

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

    working with mutable time- varying values. FRP
  5. 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
  6. What and How What and how NSArray *words = ...;

    for (NSUInteger index = 0; index < words.count; index++) { NSString *word = words[index]; // do stuff }
  7. 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 }
  8. What and How What and how NSMutableArray *uppercasedWords = [NSMutableArray

    array]; for (NSString *word in words) { [uppercasedWords addObject:word.uppercaseString]; }
  9. 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; }];
  10. Key concepts Avoids state and mutable data Any computation is

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

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

    BOOL isProbablyADuck;
  13. Minimize state by deriving it State BOOL walksLikeADuck; BOOL quacksLikeADuck;

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

    program state behaves differently depending on program state
  15. 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
  16. Reactive programming – programming paradigm oriented around data flows and

    the propagation of changes. Reactive Programming
  17. Reactive programming – programming paradigm oriented around data flows and

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

    11 a = b + c
  19. Data Changes Propagation Imperative approach b = 10 c =

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

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

    11 a = b + c (21) b = 11 a = ? (21)
  22. 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)
  23. So What?

  24. So What? Safer & easier multithreading

  25. So What? Safer & easier multithreading Reusability

  26. So What? Safer & easier multithreading Testability Reusability

  27. So What? Safer & easier multithreading Testability Reusability Cleaner picture

    of data-flow
  28. Why not KVO?

  29. Why not KVO? Key Value Observing – mechanism that allows

    objects to be notified of changes to specified properties of other objects.
  30. 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
  31. 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 { // . . . }
  32. 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
  33. Why not KVO? Unlike KVO, in ReactiveCocoa and FRP in

    general you also can:
  34. 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
  35. Bindings Developing for Mac OS X reveals Bindings. allow programming

    in IB replace boilerplate glue code
  36. 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
  37. Basic Concepts Signals Events

  38. Signals Signal – is a time varying value

  39. Signals Signal – is a time varying value int a

    = 0 a = 1 a = 2 . . . a = n
  40. Signals Signal – is a time varying value int a

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

    subscribers:
  42. Events Signals send three different types of events to their

    subscribers: next – provides a new value from the stream.
  43. 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.
  44. 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.
  45. ReactiveCocoa Basics Stream Sequence Signal

  46. 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)
  47. map filter flatten concat reduce fold merge combineLatest switchToLatest .

    . . ReactiveCocoa Toolset
  48. Some practice

  49. Subscribing to object changes [RACObserve(self, username) subscribeNext:^(NSString *newName){ NSLog(@"%@", newName);

    }];
  50. Filtering object with value

  51. [[RACObserve(self, username) filter:^(NSString *newName) { return [newName hasPrefix:@"a"]; }] subscribeNext:^(NSString

    *newName) { NSLog(@"%@", newName); }]; Filtering object with value
  52. 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
  53. 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
  54. 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
  55. 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
  56. 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."); }];
  57. 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"];
  58. 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
  59. What else? FRP-based languages and frameworks: Elm ClojureScript C# –

    Rx JavaScript – Flapjax, RxJS, Bacon.js, Java – RxJava Ruby – Frapuccino
  60. (Thanks!)