Slide 1

Slide 1 text

RACify Dave Lee @kastiglione RACDC 2014

Slide 2

Slide 2 text

RACSignalify

Slide 3

Slide 3 text

Stealth Signals • Blocks • Delegates • Notifications • Errors • Target-Action • KVO • Method Overriding

Slide 4

Slide 4 text

Bridging the Gap • +[RACSignal  defer:]   • -­‐[NSNotificationCenter  rac_addObserverForName:object:]   • -­‐[NSObject  rac_signalForSelector:]   • +[RACSignal  createSignal:]   • RACObserve()

Slide 5

Slide 5 text

[RACSignal  new]

Slide 6

Slide 6 text

[RACSignal  return:value]

Slide 7

Slide 7 text

[RACSignal  error:error]

Slide 8

Slide 8 text

[RACSignal  empty]

Slide 9

Slide 9 text

[RACSubject  subject]

Slide 10

Slide 10 text

+[RACSignal  defer:] [RACSignal  defer:^{     return  [RACSignal  return:@(arc4random())];   }]

Slide 11

Slide 11 text

+[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)];   }]

Slide 12

Slide 12 text

+[RACSignal  createSignal:] [RACSignal  createSignal:^(id

Slide 13

Slide 13 text

+[RACSignal  createSignal:] [RACSignal  createSignal:^(id

Slide 14

Slide 14 text

AFNetworking

Slide 15

Slide 15 text

AFHTTPRequestOperationManager  *manager  =  …;   [manager  GET:URLString  parameters:params     success:^(AFHTTPRequestOperation  *op,  id  response)  {       //  Success-­‐y     }  failure:^(AFHTTPRequestOperation  *op,  NSError  *e)  {       //  Fail-­‐y     }];

Slide 16

Slide 16 text

[RACSignal  createSignal:^(id

Slide 17

Slide 17 text

[RACSignal  createSignal:^(id

Slide 18

Slide 18 text

Core Data

Slide 19

Slide 19 text

__block  NSArray  *results;   [managedObjectContext  performBlock:^{     NSError  *error;     results  =  [managedObjectContext       executeFetchRequest:fetchRequest  error:&error];   }];

Slide 20

Slide 20 text

[RACSignal  createSignal:^(id  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];       }     }];  

Slide 21

Slide 21 text

!   [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;   }];  

Slide 22

Slide 22 text

Core Location

Slide 23

Slide 23 text

CLLocationManager  *locationManager  =  …   locationManager.delegate  =  self;   static  volatile  int32_t  subscriberCount  =  0;

Slide 24

Slide 24 text

[RACSignal  createSignal:^(id  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;  

Slide 25

Slide 25 text

  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];  

Slide 26

Slide 26 text

    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];         }       }];   }];

Slide 27

Slide 27 text

AFNetworking

Slide 28

Slide 28 text

! RACSignal  *isReachable  =  [RACObserve(     reachabilityManager,  networkReachabilityStatus)     map:^(NSNumber  *networkReachabilityStatus)  {       switch  (networkReachabilityStatus.intValue)  {         case  AFNetworkReachabilityStatusReachableViaWWAN:         case  AFNetworkReachabilityStatusReachableViaWiFi:           return  @YES;       }       return  @NO;     }];

Slide 29

Slide 29 text

Notifications

Slide 30

Slide 30 text

UIApplicationWillEnterForegroundNotification   UIApplicationDidEnterBackgroundNotification   UIApplicationWillResignActiveNotification   UIApplicationDidBecomeActiveNotification

Slide 31

Slide 31 text

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]];

Slide 32

Slide 32 text

More… • Use -­‐rac_signalForSelector:, everywhere. • Check out the AppKit and UIKit extensions in RAC