Skip to content

Latest commit

 

History

History
280 lines (168 loc) · 4.45 KB

File metadata and controls

280 lines (168 loc) · 4.45 KB

ReactiveCocoa Lessons Learned

Rob Pearson @robpearson


Maple Pixel

Everyday Transit 1.0

coming soon ...

![fit](Maple Pixel Logo Mark.png) fit


FrieNDA

^ Unreleased App. Code Examples. Please be kind ...


Everyday ReactiveCocoa

  1. Functional Programming Briefly
  2. Signals and Pipelines
  3. RAC Lessons Learned

Functional Programming Briefly


fit


fit

^ Purity: f(x) = x + 1 ^ Output is calculated soley on its inputs ^ Repeatable ^ No Side Effects ^ Immutable Data

^ Higher Order Functions: Input or Output is a Function ^ map, reduce, filter, concat, take ...


Signals and Pipelines


Demo


fit


Transit Dashboard Pipeline

Inputs:

  • List of Everyday Trips (Favourites)
  • GPS Location
  • Time

Outputs:

  • Next Transit Trip

^ It's all about Inputs and Outputs


Pipelines ==

RACSignals


RACSignal Example

[RACSignal createSignal:^(id<RACSubscriber subscriber) {

  // Do Something
	u_int32_t r = arc4random();

	// Start (and in this case complete) the signal.
	[subscriber sendNext:@(r)];
	[subscriber sendCompleted];

	return (RACDisposable *)nil;
}];

So we have Pipelines/Signals. Now what?


Two Options

RAC(self, viewModel.something)

RACSignal subscribeNext: error: completed:


RAC Lessons Learned


fit


KVO

^ This is worth the dependency


No, Seriously ... KVO!

^ This is worth the dependency


Key Value Observing

// Bind Transit Trips to Table View
[RACObserve(self.viewModel, everydayTransitTrips) subscribeNext:^(id x) {
    @strongify(self);

    [self.tableView reloadData];

}];

Work with Protocols


rac_signalForSelector

[[self rac_signalForSelector:@selector(searchBar:textDidChange:) fromProtocol:@protocol(UISearchBarDelegate)] subscribeNext:^(RACTuple *value) {
    @strongify(self);

    UISearchBar *searchBar = value.first;

    if (searchBar == self.departingLocationsSearchBar) {
        [self.viewModel filterDepartingLocationsByName:self.departingLocationsSearchBar.text];
    }
    else {
        [self.viewModel filterArrivingLocationsByName:self.arrivingLocationsSearchBar.text];
    }

}];

Take advantage of RAC Category Methods

^ Touch Events, Notifications, Reachability etc.


NotificationCentre

RACSignal *appActiveSignal = [[[[NSNotificationCenter.defaultCenter
        rac_addObserverForName:UIApplicationDidBecomeActiveNotification object:nil] mapReplace:@YES]
        startWith:@YES]
        setNameWithFormat:@"%@ appActive", self];

Signal Tips and Tricks


Reactive Timer 1

Map Time


Reactive Timer 1

    [[[[[RACSignal interval:60 onScheduler:[RACScheduler scheduler]]
            map:^id(NSDate *timestamp) {
                @strongify(self);

                  if (self.hasEverydayTrips != nil && [@(YES) isEqualToNumber:self.hasEverydayTrips]) {
                      return @"SEQ";
                  }
                  else {
                      return @"Everyday Transit";
                  }
            }]
            startWith:@"Everyday Transit"]
            distinctUntilChanged]
            deliverOn:[RACScheduler mainThreadScheduler]];

Reactive Timer 2

Empty Signal with a delay.


Reactive Timer 2

    RACSignal *nextTransitTripIntervalSignal = [RACSignal interval:1 onScheduler:[RACScheduler scheduler]];
    RACSignal *currentUserLocationRefreshDelay = [[RACSignal empty] delay:60];
    RACSignal *currentUserLocationRefreshSignal = [[[self.locationService.locationSignal
            take:1]
            concat:currentUserLocationRefreshDelay]
            repeat];

Real Power is combing and chaining signals


Protips

  • Start by reading IntroToRx.com
  • Start small and iterate.
  • Logging w/ Something like Cocoalumberjack
  • Asks questions by opening issues at http://github.com/ReactiveCocoa/

Challenges

  • Thinking like a Functional Programmer
  • ReactiveCocoa Doco
  • Debugging

References


Questions?