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

RACDC – RACify

Dave Lee
September 09, 2014

RACDC – RACify

A run through examples of building ReactiveCocoa APIs out of traditional objective-c APIs.

Dave Lee

September 09, 2014
Tweet

More Decks by Dave Lee

Other Decks in Programming

Transcript

  1. Stealth Signals • Blocks • Delegates • Notifications • Errors

    • Target-Action • KVO • Method Overriding
  2. Bridging the Gap • +[RACSignal  defer:]   • -­‐[NSNotificationCenter  rac_addObserverForName:object:]

      • -­‐[NSObject  rac_signalForSelector:]   • +[RACSignal  createSignal:]   • RACObserve()
  3. +[RACSignal  defer:] [RACSignal  defer:^{     //  Perform  per-­‐subscription  side

     effects.     u_int32_t  r  =  arc4random();   !   //  Start  (and  in  this  case  complete)  the  signal.     return  [RACSignal  return:@(r)];   }]
  4. +[RACSignal  createSignal:] [RACSignal  createSignal:^(id<RACSubscriber  subscriber)  {     //  Perform

     per-­‐subscription  side  effects.     u_int32_t  r  =  arc4random();   !   //  Start  (and  in  this  case  complete)  the  signal.     [subscriber  sendNext:@(r)];     [subscriber  sendCompleted];   !   return  (RACDisposable  *)nil;   }]
  5. AFHTTPRequestOperationManager  *manager  =  …;   [manager  GET:URLString  parameters:params    

    success:^(AFHTTPRequestOperation  *op,  id  response)  {       //  Success-­‐y     }  failure:^(AFHTTPRequestOperation  *op,  NSError  *e)  {       //  Fail-­‐y     }];
  6. [RACSignal  createSignal:^(id<RACSubscriber  subscriber)  {     [manager  GET:URLString  parameters:params  

        success:^(AFHTTPRequestOperation  *op,  id  response)  {         [subscriber  sendNext:response];         [subscriber  sendCompleted];       }  failure:^(AFHTTPRequestOperation  *op,  NSError  *e)  {         [subscriber  sendError:e];       }];   }]
  7. [RACSignal  createSignal:^(id<RACSubscriber  subscriber)  {     NSOperation  *operation  =  [manager

          GET:URLString  parameters:params       success:^(AFHTTPRequestOperation  *op,  id  response)  {         [subscriber  sendNext:response];         [subscriber  sendCompleted];       }  failure:^(AFHTTPRequestOperation  *op,  NSError  *e)  {         [subscriber  sendError:e];       }];   !   return  [RACDisposable  disposableWithBlock:^{       [operation  cancel];     }];   }]
  8. __block  NSArray  *results;   [managedObjectContext  performBlock:^{     NSError  *error;

        results  =  [managedObjectContext       executeFetchRequest:fetchRequest  error:&error];   }];
  9. [RACSignal  createSignal:^(id<RACSubscriber>  subscriber)  {     RACDisposable  *disposable  =  [RACDisposable

     new];   !   [managedObjectContext  performBlock:^{       if  (disposable.disposed)  return;   !     NSError  *error;       NSArray  *results  =  [managedObjectContext         performFetch:fetchRequest  error:&error];   !     if  (results  !=  nil)  {         [subscriber  sendNext:results];         [subscriber  sendCompleted];       }  else  {         [subscriber  sendError:error];       }     }];  
  10. !   [managedObjectContext  performBlock:^{       if  (disposable.disposed)  return;

      !     NSError  *error;       NSArray  *results  =  [managedObjectContext         performFetch:fetchRequest  error:&error];   !     if  (results  !=  nil)  {         [subscriber  sendNext:results];         [subscriber  sendCompleted];       }  else  {         [subscriber  sendError:error];       }     }];   !   return  disposable;   }];  
  11. [RACSignal  createSignal:^(id<RACSubscriber>  subscriber)  {     RACSignal  *locations  =  [[self

          rac_signalForSelector:@selector(…didUpdateLocations:)       fromProtocol:@protocol(CLLocationManagerDelegate)]       reduceEach:^(id  _,NSArray  *locations)  {         return  locations;       }];   !   RACSignal  *error  =  [[[[self       rac_signalForSelector:@selector(…didFailWithError:)       fromProtocol:@protocol(CLLocationManagerDelegate)]       reduceEach:^(id  _,  NSError  *error)  {         return  error;       }]       filter:^  BOOL  (NSError  *error)  {         //  Documentation  says  Core  Location  will  keep         //  will  keep  trying  after  kCLErrorLocationUnknown.         return  error.code  !=  kCLErrorLocationUnknown;  
  12.   RACSignal  *error  =  [[[[self       rac_signalForSelector:@selector(…didFailWithError:)  

        fromProtocol:@protocol(CLLocationManagerDelegate)]       reduceEach:^(id  _,  NSError  *error)  {         return  error;       }]       filter:^  BOOL  (NSError  *error)  {         //  Documentation  says  Core  Location  will  keep         //  will  keep  trying  after  kCLErrorLocationUnknown.         return  error.code  !=  kCLErrorLocationUnknown;       }]       flattenMap:^(NSError  *error)  {         return  [RACSignal  error:error];       }];   !     RACDisposable  *disposable  =  [[RACSignal         merge:@[  locations,  error  ]]         subscribe:subscriber];  
  13.     RACDisposable  *disposable  =  [[RACSignal        

    merge:@[  locations,  error  ]]         subscribe:subscriber];   !     if  (OSAtomictIncrement32(&subscriberCount)  ==  1)  {         [locationManager  startUpdatingLocation];       }  else  {         [subscriber  sendNext:locationManager.location];       }   !     return  [RACDisposable  disposableWithBlock:^{         [disposable  dispose];         if  (OSAtomictDecrement32(&subscriberCount)  ==  0)  {           [locationManager  stopUpdatingLocation];         }       }];   }];
  14. ! RACSignal  *isReachable  =  [RACObserve(     reachabilityManager,  networkReachabilityStatus)  

      map:^(NSNumber  *networkReachabilityStatus)  {       switch  (networkReachabilityStatus.intValue)  {         case  AFNetworkReachabilityStatusReachableViaWWAN:         case  AFNetworkReachabilityStatusReachableViaWiFi:           return  @YES;       }       return  @NO;     }];
  15. RACSignal  *isForeground  =  [RACSignal  merge:@[     [[defaultCenter    

      rac_addObserverForName:WillEnterForeground  …]       mapReplace:@YES]     [[defaultCenter       rac_addObserverForName:DidEnterBackground  …]       mapReplace:@NO]   ]];   ! RACSignal  *hasLaunchedActive  =  [RACSignal     if:isForeground     then:[[defaultCenter       rac_addObserverForName:DidBecomeActive  …]  take:1]     else:[RACSignal  empty]];