Peter Friese, Zühlke Engineering

RestKit
From Zero to Hero                         that?!
                                   What’s
Peter Friese




   @peterfriese
   peter.friese@zuehlke.com
   xing.to/peter
   http://peterfriese.de
What we will cover today


 1   Challenges

 2   How can RestKit help?

 3   Demos!
Challenges...

                                            Differe
                                                    nt   Data F
                                                               ormats
                         ky Con nectivity
                      Fla

O ffline Data Access
How can RestKit help?
                        2
RestKit Features

    Integrated HTTP Stack
    Pluggable Parser
    Object Mapping
    Core Data Integration
    UI Integration
Integrated HTTP Stack
 ✔   Base URLs
 ✔   Custom Headers
 ✔   Network Indicator
 ✔   Performing Requests
 ✔   Background Processing
 ✔   Authentication
 ✔   Request caching
Base URL



// create client
RKClient *client =
  [RKClient clientWithBaseURL:@"http://github.org"];
Custom Headers


// send this field with each request
[client
  setValue:
    [[[UIDevice currentDevice] identifierForVendor] UUIDString]
  forHTTPHeaderField:@"X-UDID"];
Network Indicator



client.requestQueue.showsNetworkActivityIndicatorWhenBusy = YES;
Network Indicator



client.requestQueue.showsNetworkActivityIndicatorWhenBusy = YES;
Perform Requests

 - (IBAction)forkYou:(id)sender {
     [[RKClient sharedClient]
       get:@"https://github.com/fluidicon.png"
       delegate:self];
 }

 - (void)request:(RKRequest *)request
   didLoadResponse:(RKResponse *)response
 {
     if ([response isSuccessful]) {
         UIImage *image =
          [UIImage imageWithData:[response body]];
         self.imageView.image = image;
     }
 }
Requests with Blocks
- (IBAction)forkYouWithBlocks
                                          Bloc ks FTW
{
  self.imageView.image = nil;
  [[RKClient sharedClient]
    get:@"http://github.com/fluidicon.png"
    usingBlock:^(RKRequest *request)
  {
    [request setOnDidLoadResponse:^(RKResponse *response)
    {
      if (response.isSuccessful)
      {
        UIImage *image =
          [UIImage imageWithData:response.body];
        self.imageView.image = image;
      }
    }];
  }];
}
Background Processing
[request setBackgroundPolicy:
  RKRequestBackgroundPolicyContinue];


                    // do noth
                               ing
                    RKRequest
                              Backgroun
                                        dP  olicyNone
                   // cancel
                             request
                   RKRequest
                             Backgroun
                                       dPolicyC   ancel
                   // continu
                              e until ext
                   RKRequest             ra time exp
                             Backgroun               ires
                                        dPolicyCon
                                                   tinue
                  // requeu
                            e upon app
                  RKRequest              restart
                            Backgroun
                                       dPolicyReq
                                                  ueue
Authentication
[client
  setAuthenticationType:RKRequestAuthenticationTypeHTTPBasic];


                                           n
                         au thenticatio
             // disable             ica tionTypeNo
                                                      ne
             RKReque   stAuthent
                                                          on
                                          aut o negotiati
                          C onnection
              // NSURL                    io nTypeHTT
                                                         P
                         tA  uthenticat
              RKReques
                                       h
                          Basic Aut                           sic
               // HTTP                         Ty peHTTPBa
                              ut hentication
               R KRequestA

                //  OAuth 1.0                  nTypeOAu
                                                           th
                                          atio
                           t Authentic
                RKReques
                               .0
                 / / OAuth 2                    nT ypeOAuth
                                                              2
                                u thenticatio
                 R KRequestA
Request caching
client.cachePolicy =
  RKRequestCachePolicyLoadIfOffline |
  RKRequestCachePolicyTimeout;
                                    // don’t u
                                               se request
                                   RKRequest                cache
                                               CachePolic
                                                           yNone
                                   // use ca
                                             che if off
                                  RKRequest             line
                                              CachePolic
                                                          yLoadIfOf
                                  // in case                        fline
                                              of an error
                                 RKRequest
                                             CachePolic
                                                         yLoadOnEr
                                 // use ET                         ror
                                            ags
                                RKRequest
                                            CachePolic
                                                        yEtag
                                // if we’ve
                                             got data st
                               RKRequest                 ored
                                           CachePolic
                                                       yEnabled
                               // in case
                                           of a timeo
                               RKRequest              ut
                                          CachePolic
                                                      yTimeout
Object Mapping

                     XML
                     (legacy)



                   JSON
                 (new and cool)
Object Mapping
                 Dep
                       rec
                          ate
                           XMLd
                              (legacy)



                             JSON
                         (new and cool)
Object Mapping
 ✔   Simple Object Mapping
 ✔   Mapping Relationships
 ✔   Inverse Mappings
 ✔   Serialization Mappings
Object Mapping
Object Mapping




             ->
                 No Ha
                       #
                      shmaps
Object Mapping

                 @interface GithubUser : NSObject

                 @property (strong, nonatomic)
                   NSNumber *id;
                 @property (strong, nonatomic)
                   NSString *name;


          ->
                 @property (strong, nonatomic)
                   NSString *location;
                 @property (strong, nonatomic)
                   NSString *followers;
                 @property (strong, nonatomic)
                   NSString *email;
                 @property (strong, nonatomic)
                   NSString *following;

                 @end
Object Mapping

                 @interface GithubUser : NSObject

                 @property (strong, nonatomic)
                   NSNumber *id;
                 @property (strong, nonatomic)
                   NSString *name;


          ->
                 @property (strong, nonatomic)
                   NSString *location;
                 @property (strong, nonatomic)
                   NSString *followers;
                 @property (strong, nonatomic)
                   NSString *email;
                 @property (strong, nonatomic)
                   NSString *following;

                 @end
Object Mapping

                                    @interface GithubUser : NSObject

                                    @property (strong, nonatomic)
{                                     NSNumber *id;
    id: 232107,                     @property (strong, nonatomic)
    name: "Peter Friese",             NSString *name;
    location: "Hamburg",            @property (strong, nonatomic)
    followers: 42,                    NSString *location;
    email: “peter@peterfriese.de,   @property (strong, nonatomic)
    following: 36,                    NSString *followers;
}                                   @property (strong, nonatomic)
                                      NSString *email;
                                    @property (strong, nonatomic)
                                      NSString *following;

                                    @end
Object Mapping
     RKObjectMapping *objectMapping =
       [RKObjectMapping mappingForClass:[GithubUser class]];




{                                      @interface GithubUser : NSObject
    id: 232107,
    name: "Peter Friese",              @property (strong, nonatomic)
    location: "Hamburg",                 NSNumber *id;
    followers: 42,                     @property (strong, nonatomic)
    email: “peter@peterfriese.de,        NSString *name;
    following: 36,                     @property (strong, nonatomic)
}                                        NSString *location;
                                       @property (strong, nonatomic)
                                         NSString *followers;
Object Mapping
     RKObjectMapping *objectMapping =
       [RKObjectMapping mappingForClass:[GithubUser class]];




                                            register mapping
                                               for a class


{                                      @interface GithubUser : NSObject
    id: 232107,
    name: "Peter Friese",              @property (strong, nonatomic)
    location: "Hamburg",                 NSNumber *id;
    followers: 42,                     @property (strong, nonatomic)
    email: “peter@peterfriese.de,        NSString *name;
    following: 36,                     @property (strong, nonatomic)
}                                        NSString *location;
                                       @property (strong, nonatomic)
                                         NSString *followers;
Object Mapping
     RKObjectMapping *objectMapping =
       [RKObjectMapping mappingForClass:[GithubUser class]];
     [objectMapping mapKeyPath:@"id"
                    toAttribute:@"id"];
     [objectMapping mapKeyPath:@"name"
                    toAttribute:@"name"];   register mapping
                                               for a class


{                                      @interface GithubUser : NSObject
    id: 232107,
    name: "Peter Friese",              @property (strong, nonatomic)
    location: "Hamburg",                 NSNumber *id;
    followers: 42,                     @property (strong, nonatomic)
    email: “peter@peterfriese.de,        NSString *name;
    following: 36,                     @property (strong, nonatomic)
}                                        NSString *location;
                                       @property (strong, nonatomic)
                                         NSString *followers;
Object Mapping
     RKObjectMapping *objectMapping =
       [RKObjectMapping mappingForClass:[GithubUser class]];
     [objectMapping mapKeyPath:@"id"
                    toAttribute:@"id"];
     [objectMapping mapKeyPath:@"name"
                                            re       coapping
                                               gister m nfigur
                                                  mapclass e
                    toAttribute:@"name"];

                                                for ping (KV
                                                               C)

{                                      @interface GithubUser : NSObject
    id: 232107,
    name: "Peter Friese",              @property (strong, nonatomic)
    location: "Hamburg",                 NSNumber *id;
    followers: 42,                     @property (strong, nonatomic)
    email: “peter@peterfriese.de,        NSString *name;
    following: 36,                     @property (strong, nonatomic)
}                                        NSString *location;
                                       @property (strong, nonatomic)
                                         NSString *followers;
GETting Objects
[[RKObjectManager sharedManager]
  loadObjectsAtResourcePath:

 usingBlock:^(RKObjectLoader *loader) {




 }];
GETting Objects
[[RKObjectManager sharedManager]
  loadObjectsAtResourcePath:
    [NSString stringWithFormat:@"/users/%@", self.userName]
  usingBlock:^(RKObjectLoader *loader) {

   [loader setObjectMapping:self.mapping];




 }];
GETting Objects
[[RKObjectManager sharedManager]
  loadObjectsAtResourcePath:
    [NSString stringWithFormat:@"/users/%@", self.userName]
  usingBlock:^(RKObjectLoader *loader) {

   [loader setObjectMapping:self.mapping];
                                                 resource path

                                                   mapping,
                                                             as
                                               defined p
                                                         reviously

 }];
GETting Objects
[[RKObjectManager sharedManager]
  loadObjectsAtResourcePath:
    [NSString stringWithFormat:@"/users/%@", self.userName]
  usingBlock:^(RKObjectLoader *loader) {

   [loader setObjectMapping:self.mapping];
   [loader setOnDidLoadObject:^(id object) {



   }];
   [loader setOnDidFailWithError:^(NSError *error) {

   }];
 }];
GETting Objects
[[RKObjectManager sharedManager]
  loadObjectsAtResourcePath:
    [NSString stringWithFormat:@"/users/%@", self.userName]
  usingBlock:^(RKObjectLoader *loader) {

   [loader setObjectMapping:self.mapping];
   [loader setOnDidLoadObject:^(id object) {

          happy case :-)
   }];
   [loader setOnDidFailWithError:^(NSError *error) {

   }];    sad unhappy case :-(
 }];
GETting Objects
[[RKObjectManager sharedManager]
  loadObjectsAtResourcePath:
    [NSString stringWithFormat:@"/users/%@", self.userName]
  usingBlock:^(RKObjectLoader *loader) {

   [loader setObjectMapping:self.mapping];
   [loader setOnDidLoadObject:^(id object) {
     [self.root bindToObject:object];
     [self.quickDialogTableView reloadData];

   }];
   [loader setOnDidFailWithError:^(NSError *error) {

   }];    sad unhappy case :-(
 }];
GETting Objects
[[RKObjectManager sharedManager]
  loadObjectsAtResourcePath:
    [NSString stringWithFormat:@"/users/%@", self.userName]
  usingBlock:^(RKObjectLoader *loader) {
    [SVProgressHUD showWithStatus:@"Loading..."];
    [loader setObjectMapping:self.mapping];
    [loader setOnDidLoadObject:^(id object) {
      [self.root bindToObject:object];
      [self.quickDialogTableView reloadData];
      [SVProgressHUD dismiss];
    }];
    [loader setOnDidFailWithError:^(NSError *error) {
      [SVProgressHUD showErrorWithStatus:@"Problem loading user"];
    }];
  }];
GETting Objects
[[RKObjectManager sharedManager]
  loadObjectsAtResourcePath:
    [NSString stringWithFormat:@"/users/%@", self.userName]
  usingBlock:^(RKObjectLoader *loader) {
    [SVProgressHUD showWithStatus:@"Loading..."];
    [loader setObjectMapping:self.mapping];
    [loader setOnDidLoadObject:^(id object) {
                                                    heads up
      [self.root bindToObject:object];
      [self.quickDialogTableView reloadData];
                                                               !
      [SVProgressHUD dismiss];
    }];
    [loader setOnDidFailWithError:^(NSError *error) {
      [SVProgressHUD showErrorWithStatus:@"Problem loading user"];
    }];
  }];
GETting Objects
[[RKObjectManager sharedManager]
  loadObjectsAtResourcePath:
    [NSString stringWithFormat:@"/users/%@", self.userName]
  usingBlock:^(RKObjectLoader *loader) {
    [SVProgressHUD showWithStatus:@"Loading..."];
    [loader setObjectMapping:self.mapping];
    [loader setOnDidLoadObject:^(id object) {
      [self.root bindToObject:object];
      [self.quickDialogTableView reloadData];
      [SVProgressHUD dismiss];
    }];
    [loader setOnDidFailWithError:^(NSError *error) {
      [SVProgressHUD showErrorWithStatus:@"Problem loading user"];
    }];
  }];
Mapping Relationships
RKObjectMapping *userMapping =
  [RKObjectMapping mappingForClass:[GithubUser class]];

RKObjectMapping *issueMapping =
  [RKObjectMapping mappingForClass:[GithubIssue class]];

[issueMapping mapKeyPath:@"user"
              toRelationship:@"user"
              withMapping:userMapping];




[
                                   @interface GithubIssue : NSObject
    {
        "number": 1347,
                                   @property NSNumber *number;
        "title": "Found a bug",
                                   @property NSString *title;
        "user": {
                                   @property GithubUser *user;
          "login": "octocat",
Mapping Relationships
RKObjectMapping *userMapping =
  [RKObjectMapping mappingForClass:[GithubUser class]];

RKObjectMapping *issueMapping =
  [RKObjectMapping mappingForClass:[GithubIssue class]];

[issueMapping mapKeyPath:@"user"
              toRelationship:@"user"
              withMapping:userMapping];




[
                                   @interface GithubIssue : NSObject
    {
        "number": 1347,
                                   @property NSNumber *number;
        "title": "Found a bug",
                                   @property NSString *title;
        "user": {
                                   @property GithubUser *user;
          "login": "octocat",
POSTing Objects
[[objectManager mappingProvider]
  setObjectMapping:issueMapping forKeyPath:@""];

RKObjectMapping *issueSerializationMapping =
  [issueMapping inverseMapping];
[[[RKObjectManager sharedManager] mappingProvider]
  setSerializationMapping:issueSerializationMapping
  forClass:[GithubIssue class]];

[[[RKObjectManager sharedManager] router]
  routeClass:[GithubIssue class]
  toResourcePath:@"/repos/:repouser/:repo/issues"
  forMethod:RKRequestMethodPOST ];

[[[RKObjectManager sharedManager] router]
  routeClass:[GithubIssue class]
  toResourcePath:@"/repos/:repouser/:repo/issues/:number"];
POSTing Objects

1: Create new object
GithubIssue *issue = [[GithubIssue alloc] init];


2: ProvideInfos for RestKit router:
issue.repouser = repouser;
issue.repo = repo;


3: POST object:
[[RKObjectManager sharedManager]
  postObject:issue usingBlock:^(RKObjectLoader *loader){
    loader.onDidLoadResponse = ^(RKResponse *response) {
      [self dismissViewControllerAnimated:YES completion:nil];
    }
}];
Core Data Integration

     Offline Data Access




             Remember?
Core Data Integration

   Change Mapped Objects
   Add a Core Data Model
   Register a Managed Object Store

   Adjust Object Mappings
   Adjust Object Creation
   Fetch Data from DB / Backend
Change Mapped Objects

 Header                     Header
 @interface GithubUser      @interface GithubUser
   : NSObject                 : NSManagedObject


 Module                     Module
 @synthesize   id;          @dynamic   id;
 @synthesize   login;       @dynamic   login;
 @synthesize   name;        @dynamic   name;
 @synthesize   company;     @dynamic   company;
 @synthesize   location;    @dynamic   location;
 @synthesize   blog;        @dynamic   blog;
 @synthesize   following;   @dynamic   following;
 @synthesize   followers;   @dynamic   followers;
 @synthesize   email;       @dynamic   email;
Add a Core Data Model
Add a Core Data Model

                 @interface GithubUser
                   : NSObject
Add a Core Data Model

                 @interface GithubUser
                   : NSObject




                    Keep in mind:
                 Assign respect
                                 ive
                classes to ma
                               naged
                     objects!
Register a Managed Object Store



  // set up object manager
  RKObjectManager *objectManager =
    [RKObjectManager
      objectManagerWithBaseURL:@"https://api.github.com"];

  // set up backing data store
  objectManager.objectStore =
    [RKManagedObjectStore
      objectStoreWithStoreFilename:@"github.sqlite"];
Adjust Object Mappings


RKObjectMapping *userMapping =
  [RKObjectMapping mappingForClass:[GithubUser class]];




RKManagedObjectMapping *userMapping =
  [RKManagedObjectMapping mappingForClass:[GithubUser class]
                     inManagedObjectStore:objectStore];
Adjust Object Creation
 GithubIssue *issue = [[GithubIssue alloc] init];



 GithubIssue *issue = [GithubIssue object];




  + (id)object {
                                      lloc]
     i d object = [[self a                        ty]
        initWi t h E n t i t y :[ s e l f e n t i
                                                    ext:
        insertIn   toManagedObjectCont                                  ead]];
                                            ext c   ontextForCurrentThr
          [ NSManagedObjectCont
                                                ];
     return   [object autorelease
   }
Fetch Data from DB / Backend
Online of offline?
 if ([[RKObjectManager sharedManager] isOnline]) {
   [self fetchDataFromRemote];
 }
 else {
   [self fetchDataFromDataStore];
 }


Offline - Fetch from DB
 - (void)fetchDataFromDataStore {
   NSFetchRequest *request =
     [[[RKObjectManager sharedManager] mappingProvider]
       fetchRequestForResourcePath:self.resourcePath];
   self.repos = [GithubRepo objectsWithFetchRequest:request];
   [self.tableView reloadData];
 }
Fetch Data from DB / Backend
Online - Fetch from Backend
- (void)fetchDataFromRemote {
  [[RKObjectManager sharedManager]
    loadObjectsAtResourcePath:[self resourcePath]
    usingBlock:^(RKObjectLoader *loader) {
      [loader setOnDidLoadObjects:^(NSArray *objects) {
        self.repos = objects;
        [self.tableView reloadData];
      }];
  }];
}
Fetch Data from DB / Backend
Reconnect after offline
- (void)reachabilityChanged:(NSNotification*)notification {
  RKReachabilityObserver* observer =
    (RKReachabilityObserver*)[notification object];

    if ([observer isNetworkReachable]) {
      if (![self.view isHidden]) {
        [self fetchDataFromRemote];
      }
    }
    else {
      if (![self.view isHidden]) {
        [self fetchDataFromDataStore];
      }
    }
}
Sync Manager
 https://github.com/RestKit/RestKit/pull/573
Seeding your DB
 Generate seed
[RKManagedObjectSeeder
  generateSeedDatabaseWithObjectManager:objectManager
  fromFiles:@"repos.json", nil];

Import seed
RKManagedObjectStore *objectStore = [RKManagedObjectStore
  objectStoreWithStoreFilename:@"github.sqlite"
  usingSeedDatabaseName:@"seed_db.sqlite"
  managedObjectModel:nil
  delegate:nil];
Putting it All Together
Putting it All Together



  Wait a minute - can we do this simpler?
RestKit UI

 ✔   Static Tables
 ✔   Networked Table
 ✔   Forms
RestKit UI - Networked Table
self.tableController =
  [[RKObjectManager sharedManager]
    fetchedResultsTableControllerForTableViewController:self];

self.tableController.resourcePath = [self resourcePath];
RestKit UI - Networked Table
self.tableController =
  [[RKObjectManager sharedManager]
    fetchedResultsTableControllerForTableViewController:self];

self.tableController.resourcePath = [self resourcePath];

Sorting
NSSortDescriptor *descriptor =
  [NSSortDescriptor
    sortDescriptorWithKey:@"createdAt"
    ascending:NO];

self.tableController.sortDescriptors =
  [NSArray arrayWithObject:descriptor];
RestKit UI - Networked Table
self.tableController =
  [[RKObjectManager sharedManager]
    fetchedResultsTableControllerForTableViewController:self];

self.tableController.resourcePath = [self resourcePath];



   her nic e stuff
Ot
self.tableController.autoRefreshFromNetwork = YES;
self.tableController.pullToRefreshEnabled = YES;
RestKit UI - Cell Mapping

RKTableViewCellMapping *cellMapping =
  [RKTableViewCellMapping cellMapping];

cellMapping.style = UITableViewCellStyleValue1;
[cellMapping
  mapKeyPath:@"name"
  toAttribute:@"textLabel.text"];

[cellMapping
  mapKeyPath:@"openIssues"
  toAttribute:@"detailTextLabel.text"];

[cellMapping
  setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];

[tableController mapObjectsWithClass:
  [GithubRepo class]
    toTableCellsWithMapping:cellMapping];
Thanks!




http://www.slideshare.net/peterfriese

                         hat litt le spot
             Reme mber t
                     he firs t slide?
                on t
Awesome Unicorn Coloring Slide
Anyway, Thanks!

 Peter Friese
                        om
 peter.friese@zuehlke.c

   hlke Engineering Gm
                       bH
                                      Available for cons
 Zü
 Am Sandtorkai 66                                        ulting,
 20457 Hamburg                        projects, discuss
                                                        ing
  +49 151 108 604 72                  all things mobile
                                       - and frosty bever
                                                          ages!




                             CouchDB Mobile - from Couch to 5K in 1 Hour

RestKit - From Zero to Hero

  • 1.
    Peter Friese, ZühlkeEngineering RestKit From Zero to Hero that?! What’s
  • 2.
    Peter Friese @peterfriese peter.friese@zuehlke.com xing.to/peter http://peterfriese.de
  • 3.
    What we willcover today 1 Challenges 2 How can RestKit help? 3 Demos!
  • 4.
    Challenges... Differe nt Data F ormats ky Con nectivity Fla O ffline Data Access
  • 5.
  • 6.
    RestKit Features Integrated HTTP Stack Pluggable Parser Object Mapping Core Data Integration UI Integration
  • 7.
    Integrated HTTP Stack ✔ Base URLs ✔ Custom Headers ✔ Network Indicator ✔ Performing Requests ✔ Background Processing ✔ Authentication ✔ Request caching
  • 8.
    Base URL // createclient RKClient *client = [RKClient clientWithBaseURL:@"http://github.org"];
  • 9.
    Custom Headers // sendthis field with each request [client setValue: [[[UIDevice currentDevice] identifierForVendor] UUIDString] forHTTPHeaderField:@"X-UDID"];
  • 10.
  • 11.
  • 12.
    Perform Requests -(IBAction)forkYou:(id)sender { [[RKClient sharedClient] get:@"https://github.com/fluidicon.png" delegate:self]; } - (void)request:(RKRequest *)request didLoadResponse:(RKResponse *)response { if ([response isSuccessful]) { UIImage *image = [UIImage imageWithData:[response body]]; self.imageView.image = image; } }
  • 13.
    Requests with Blocks -(IBAction)forkYouWithBlocks Bloc ks FTW { self.imageView.image = nil; [[RKClient sharedClient] get:@"http://github.com/fluidicon.png" usingBlock:^(RKRequest *request) { [request setOnDidLoadResponse:^(RKResponse *response) { if (response.isSuccessful) { UIImage *image = [UIImage imageWithData:response.body]; self.imageView.image = image; } }]; }]; }
  • 14.
    Background Processing [request setBackgroundPolicy: RKRequestBackgroundPolicyContinue]; // do noth ing RKRequest Backgroun dP olicyNone // cancel request RKRequest Backgroun dPolicyC ancel // continu e until ext RKRequest ra time exp Backgroun ires dPolicyCon tinue // requeu e upon app RKRequest restart Backgroun dPolicyReq ueue
  • 15.
    Authentication [client setAuthenticationType:RKRequestAuthenticationTypeHTTPBasic]; n au thenticatio // disable ica tionTypeNo ne RKReque stAuthent on aut o negotiati C onnection // NSURL io nTypeHTT P tA uthenticat RKReques h Basic Aut sic // HTTP Ty peHTTPBa ut hentication R KRequestA // OAuth 1.0 nTypeOAu th atio t Authentic RKReques .0 / / OAuth 2 nT ypeOAuth 2 u thenticatio R KRequestA
  • 16.
    Request caching client.cachePolicy = RKRequestCachePolicyLoadIfOffline | RKRequestCachePolicyTimeout; // don’t u se request RKRequest cache CachePolic yNone // use ca che if off RKRequest line CachePolic yLoadIfOf // in case fline of an error RKRequest CachePolic yLoadOnEr // use ET ror ags RKRequest CachePolic yEtag // if we’ve got data st RKRequest ored CachePolic yEnabled // in case of a timeo RKRequest ut CachePolic yTimeout
  • 17.
    Object Mapping XML (legacy) JSON (new and cool)
  • 18.
    Object Mapping Dep rec ate XMLd (legacy) JSON (new and cool)
  • 19.
    Object Mapping ✔ Simple Object Mapping ✔ Mapping Relationships ✔ Inverse Mappings ✔ Serialization Mappings
  • 20.
  • 21.
    Object Mapping -> No Ha # shmaps
  • 22.
    Object Mapping @interface GithubUser : NSObject @property (strong, nonatomic) NSNumber *id; @property (strong, nonatomic) NSString *name; -> @property (strong, nonatomic) NSString *location; @property (strong, nonatomic) NSString *followers; @property (strong, nonatomic) NSString *email; @property (strong, nonatomic) NSString *following; @end
  • 23.
    Object Mapping @interface GithubUser : NSObject @property (strong, nonatomic) NSNumber *id; @property (strong, nonatomic) NSString *name; -> @property (strong, nonatomic) NSString *location; @property (strong, nonatomic) NSString *followers; @property (strong, nonatomic) NSString *email; @property (strong, nonatomic) NSString *following; @end
  • 24.
    Object Mapping @interface GithubUser : NSObject @property (strong, nonatomic) { NSNumber *id; id: 232107, @property (strong, nonatomic) name: "Peter Friese", NSString *name; location: "Hamburg", @property (strong, nonatomic) followers: 42, NSString *location; email: “peter@peterfriese.de, @property (strong, nonatomic) following: 36, NSString *followers; } @property (strong, nonatomic) NSString *email; @property (strong, nonatomic) NSString *following; @end
  • 25.
    Object Mapping RKObjectMapping *objectMapping = [RKObjectMapping mappingForClass:[GithubUser class]]; { @interface GithubUser : NSObject id: 232107, name: "Peter Friese", @property (strong, nonatomic) location: "Hamburg", NSNumber *id; followers: 42, @property (strong, nonatomic) email: “peter@peterfriese.de, NSString *name; following: 36, @property (strong, nonatomic) } NSString *location; @property (strong, nonatomic) NSString *followers;
  • 26.
    Object Mapping RKObjectMapping *objectMapping = [RKObjectMapping mappingForClass:[GithubUser class]]; register mapping for a class { @interface GithubUser : NSObject id: 232107, name: "Peter Friese", @property (strong, nonatomic) location: "Hamburg", NSNumber *id; followers: 42, @property (strong, nonatomic) email: “peter@peterfriese.de, NSString *name; following: 36, @property (strong, nonatomic) } NSString *location; @property (strong, nonatomic) NSString *followers;
  • 27.
    Object Mapping RKObjectMapping *objectMapping = [RKObjectMapping mappingForClass:[GithubUser class]]; [objectMapping mapKeyPath:@"id" toAttribute:@"id"]; [objectMapping mapKeyPath:@"name" toAttribute:@"name"]; register mapping for a class { @interface GithubUser : NSObject id: 232107, name: "Peter Friese", @property (strong, nonatomic) location: "Hamburg", NSNumber *id; followers: 42, @property (strong, nonatomic) email: “peter@peterfriese.de, NSString *name; following: 36, @property (strong, nonatomic) } NSString *location; @property (strong, nonatomic) NSString *followers;
  • 28.
    Object Mapping RKObjectMapping *objectMapping = [RKObjectMapping mappingForClass:[GithubUser class]]; [objectMapping mapKeyPath:@"id" toAttribute:@"id"]; [objectMapping mapKeyPath:@"name" re coapping gister m nfigur mapclass e toAttribute:@"name"]; for ping (KV C) { @interface GithubUser : NSObject id: 232107, name: "Peter Friese", @property (strong, nonatomic) location: "Hamburg", NSNumber *id; followers: 42, @property (strong, nonatomic) email: “peter@peterfriese.de, NSString *name; following: 36, @property (strong, nonatomic) } NSString *location; @property (strong, nonatomic) NSString *followers;
  • 29.
    GETting Objects [[RKObjectManager sharedManager] loadObjectsAtResourcePath: usingBlock:^(RKObjectLoader *loader) { }];
  • 30.
    GETting Objects [[RKObjectManager sharedManager] loadObjectsAtResourcePath: [NSString stringWithFormat:@"/users/%@", self.userName] usingBlock:^(RKObjectLoader *loader) { [loader setObjectMapping:self.mapping]; }];
  • 31.
    GETting Objects [[RKObjectManager sharedManager] loadObjectsAtResourcePath: [NSString stringWithFormat:@"/users/%@", self.userName] usingBlock:^(RKObjectLoader *loader) { [loader setObjectMapping:self.mapping]; resource path mapping, as defined p reviously }];
  • 32.
    GETting Objects [[RKObjectManager sharedManager] loadObjectsAtResourcePath: [NSString stringWithFormat:@"/users/%@", self.userName] usingBlock:^(RKObjectLoader *loader) { [loader setObjectMapping:self.mapping]; [loader setOnDidLoadObject:^(id object) { }]; [loader setOnDidFailWithError:^(NSError *error) { }]; }];
  • 33.
    GETting Objects [[RKObjectManager sharedManager] loadObjectsAtResourcePath: [NSString stringWithFormat:@"/users/%@", self.userName] usingBlock:^(RKObjectLoader *loader) { [loader setObjectMapping:self.mapping]; [loader setOnDidLoadObject:^(id object) { happy case :-) }]; [loader setOnDidFailWithError:^(NSError *error) { }]; sad unhappy case :-( }];
  • 34.
    GETting Objects [[RKObjectManager sharedManager] loadObjectsAtResourcePath: [NSString stringWithFormat:@"/users/%@", self.userName] usingBlock:^(RKObjectLoader *loader) { [loader setObjectMapping:self.mapping]; [loader setOnDidLoadObject:^(id object) { [self.root bindToObject:object]; [self.quickDialogTableView reloadData]; }]; [loader setOnDidFailWithError:^(NSError *error) { }]; sad unhappy case :-( }];
  • 35.
    GETting Objects [[RKObjectManager sharedManager] loadObjectsAtResourcePath: [NSString stringWithFormat:@"/users/%@", self.userName] usingBlock:^(RKObjectLoader *loader) { [SVProgressHUD showWithStatus:@"Loading..."]; [loader setObjectMapping:self.mapping]; [loader setOnDidLoadObject:^(id object) { [self.root bindToObject:object]; [self.quickDialogTableView reloadData]; [SVProgressHUD dismiss]; }]; [loader setOnDidFailWithError:^(NSError *error) { [SVProgressHUD showErrorWithStatus:@"Problem loading user"]; }]; }];
  • 36.
    GETting Objects [[RKObjectManager sharedManager] loadObjectsAtResourcePath: [NSString stringWithFormat:@"/users/%@", self.userName] usingBlock:^(RKObjectLoader *loader) { [SVProgressHUD showWithStatus:@"Loading..."]; [loader setObjectMapping:self.mapping]; [loader setOnDidLoadObject:^(id object) { heads up [self.root bindToObject:object]; [self.quickDialogTableView reloadData]; ! [SVProgressHUD dismiss]; }]; [loader setOnDidFailWithError:^(NSError *error) { [SVProgressHUD showErrorWithStatus:@"Problem loading user"]; }]; }];
  • 37.
    GETting Objects [[RKObjectManager sharedManager] loadObjectsAtResourcePath: [NSString stringWithFormat:@"/users/%@", self.userName] usingBlock:^(RKObjectLoader *loader) { [SVProgressHUD showWithStatus:@"Loading..."]; [loader setObjectMapping:self.mapping]; [loader setOnDidLoadObject:^(id object) { [self.root bindToObject:object]; [self.quickDialogTableView reloadData]; [SVProgressHUD dismiss]; }]; [loader setOnDidFailWithError:^(NSError *error) { [SVProgressHUD showErrorWithStatus:@"Problem loading user"]; }]; }];
  • 38.
    Mapping Relationships RKObjectMapping *userMapping= [RKObjectMapping mappingForClass:[GithubUser class]]; RKObjectMapping *issueMapping = [RKObjectMapping mappingForClass:[GithubIssue class]]; [issueMapping mapKeyPath:@"user" toRelationship:@"user" withMapping:userMapping]; [ @interface GithubIssue : NSObject { "number": 1347, @property NSNumber *number; "title": "Found a bug", @property NSString *title; "user": { @property GithubUser *user; "login": "octocat",
  • 39.
    Mapping Relationships RKObjectMapping *userMapping= [RKObjectMapping mappingForClass:[GithubUser class]]; RKObjectMapping *issueMapping = [RKObjectMapping mappingForClass:[GithubIssue class]]; [issueMapping mapKeyPath:@"user" toRelationship:@"user" withMapping:userMapping]; [ @interface GithubIssue : NSObject { "number": 1347, @property NSNumber *number; "title": "Found a bug", @property NSString *title; "user": { @property GithubUser *user; "login": "octocat",
  • 40.
    POSTing Objects [[objectManager mappingProvider] setObjectMapping:issueMapping forKeyPath:@""]; RKObjectMapping *issueSerializationMapping = [issueMapping inverseMapping]; [[[RKObjectManager sharedManager] mappingProvider] setSerializationMapping:issueSerializationMapping forClass:[GithubIssue class]]; [[[RKObjectManager sharedManager] router] routeClass:[GithubIssue class] toResourcePath:@"/repos/:repouser/:repo/issues" forMethod:RKRequestMethodPOST ]; [[[RKObjectManager sharedManager] router] routeClass:[GithubIssue class] toResourcePath:@"/repos/:repouser/:repo/issues/:number"];
  • 41.
    POSTing Objects 1: Createnew object GithubIssue *issue = [[GithubIssue alloc] init]; 2: ProvideInfos for RestKit router: issue.repouser = repouser; issue.repo = repo; 3: POST object: [[RKObjectManager sharedManager] postObject:issue usingBlock:^(RKObjectLoader *loader){ loader.onDidLoadResponse = ^(RKResponse *response) { [self dismissViewControllerAnimated:YES completion:nil]; } }];
  • 42.
    Core Data Integration Offline Data Access Remember?
  • 43.
    Core Data Integration Change Mapped Objects Add a Core Data Model Register a Managed Object Store Adjust Object Mappings Adjust Object Creation Fetch Data from DB / Backend
  • 44.
    Change Mapped Objects Header Header @interface GithubUser @interface GithubUser : NSObject : NSManagedObject Module Module @synthesize id; @dynamic id; @synthesize login; @dynamic login; @synthesize name; @dynamic name; @synthesize company; @dynamic company; @synthesize location; @dynamic location; @synthesize blog; @dynamic blog; @synthesize following; @dynamic following; @synthesize followers; @dynamic followers; @synthesize email; @dynamic email;
  • 45.
    Add a CoreData Model
  • 46.
    Add a CoreData Model @interface GithubUser : NSObject
  • 47.
    Add a CoreData Model @interface GithubUser : NSObject Keep in mind: Assign respect ive classes to ma naged objects!
  • 48.
    Register a ManagedObject Store // set up object manager RKObjectManager *objectManager = [RKObjectManager objectManagerWithBaseURL:@"https://api.github.com"]; // set up backing data store objectManager.objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:@"github.sqlite"];
  • 49.
    Adjust Object Mappings RKObjectMapping*userMapping = [RKObjectMapping mappingForClass:[GithubUser class]]; RKManagedObjectMapping *userMapping = [RKManagedObjectMapping mappingForClass:[GithubUser class] inManagedObjectStore:objectStore];
  • 50.
    Adjust Object Creation GithubIssue *issue = [[GithubIssue alloc] init]; GithubIssue *issue = [GithubIssue object]; + (id)object { lloc] i d object = [[self a ty] initWi t h E n t i t y :[ s e l f e n t i ext: insertIn toManagedObjectCont ead]]; ext c ontextForCurrentThr [ NSManagedObjectCont ]; return [object autorelease }
  • 51.
    Fetch Data fromDB / Backend Online of offline? if ([[RKObjectManager sharedManager] isOnline]) { [self fetchDataFromRemote]; } else { [self fetchDataFromDataStore]; } Offline - Fetch from DB - (void)fetchDataFromDataStore { NSFetchRequest *request = [[[RKObjectManager sharedManager] mappingProvider] fetchRequestForResourcePath:self.resourcePath]; self.repos = [GithubRepo objectsWithFetchRequest:request]; [self.tableView reloadData]; }
  • 52.
    Fetch Data fromDB / Backend Online - Fetch from Backend - (void)fetchDataFromRemote { [[RKObjectManager sharedManager] loadObjectsAtResourcePath:[self resourcePath] usingBlock:^(RKObjectLoader *loader) { [loader setOnDidLoadObjects:^(NSArray *objects) { self.repos = objects; [self.tableView reloadData]; }]; }]; }
  • 53.
    Fetch Data fromDB / Backend Reconnect after offline - (void)reachabilityChanged:(NSNotification*)notification { RKReachabilityObserver* observer = (RKReachabilityObserver*)[notification object]; if ([observer isNetworkReachable]) { if (![self.view isHidden]) { [self fetchDataFromRemote]; } } else { if (![self.view isHidden]) { [self fetchDataFromDataStore]; } } }
  • 54.
  • 55.
    Seeding your DB Generate seed [RKManagedObjectSeeder generateSeedDatabaseWithObjectManager:objectManager fromFiles:@"repos.json", nil]; Import seed RKManagedObjectStore *objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:@"github.sqlite" usingSeedDatabaseName:@"seed_db.sqlite" managedObjectModel:nil delegate:nil];
  • 56.
  • 57.
    Putting it AllTogether Wait a minute - can we do this simpler?
  • 58.
    RestKit UI ✔ Static Tables ✔ Networked Table ✔ Forms
  • 59.
    RestKit UI -Networked Table self.tableController = [[RKObjectManager sharedManager] fetchedResultsTableControllerForTableViewController:self]; self.tableController.resourcePath = [self resourcePath];
  • 60.
    RestKit UI -Networked Table self.tableController = [[RKObjectManager sharedManager] fetchedResultsTableControllerForTableViewController:self]; self.tableController.resourcePath = [self resourcePath]; Sorting NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:@"createdAt" ascending:NO]; self.tableController.sortDescriptors = [NSArray arrayWithObject:descriptor];
  • 61.
    RestKit UI -Networked Table self.tableController = [[RKObjectManager sharedManager] fetchedResultsTableControllerForTableViewController:self]; self.tableController.resourcePath = [self resourcePath]; her nic e stuff Ot self.tableController.autoRefreshFromNetwork = YES; self.tableController.pullToRefreshEnabled = YES;
  • 62.
    RestKit UI -Cell Mapping RKTableViewCellMapping *cellMapping = [RKTableViewCellMapping cellMapping]; cellMapping.style = UITableViewCellStyleValue1; [cellMapping mapKeyPath:@"name" toAttribute:@"textLabel.text"]; [cellMapping mapKeyPath:@"openIssues" toAttribute:@"detailTextLabel.text"]; [cellMapping setAccessoryType:UITableViewCellAccessoryDisclosureIndicator]; [tableController mapObjectsWithClass: [GithubRepo class] toTableCellsWithMapping:cellMapping];
  • 63.
    Thanks! http://www.slideshare.net/peterfriese hat litt le spot Reme mber t he firs t slide? on t
  • 64.
  • 65.
    Anyway, Thanks! PeterFriese om peter.friese@zuehlke.c hlke Engineering Gm bH Available for cons Zü Am Sandtorkai 66 ulting, 20457 Hamburg projects, discuss ing +49 151 108 604 72 all things mobile - and frosty bever ages! CouchDB Mobile - from Couch to 5K in 1 Hour