RestKit - From Zero to Hero
Upcoming SlideShare
Loading in...5
×
 

RestKit - From Zero to Hero

on

  • 17,520 views

This talk explains what RestKit is and how it can help you build applications that sync with REST services. The code for this talk is available at https://github.com/peterfriese/RestKitFromzeroToHero

This talk explains what RestKit is and how it can help you build applications that sync with REST services. The code for this talk is available at https://github.com/peterfriese/RestKitFromzeroToHero

Statistics

Views

Total Views
17,520
Views on SlideShare
14,133
Embed Views
3,387

Actions

Likes
19
Downloads
248
Comments
8

12 Embeds 3,387

http://www.scoop.it 2888
http://lanyrd.com 438
https://twitter.com 39
http://www.techgig.com 5
http://www.linkedin.com 4
http://webcache.googleusercontent.com 3
http://coderwall.com 2
https://si0.twimg.com 2
http://hootsuite.scoop.it 2
http://translate.googleusercontent.com 2
http://twitter.com 1
http://www.m.techgig.com 1
More...

Accessibility

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
  • Nice work :)
    Are you sure you want to
    Your message goes here
    Processing…
  • Hello!

    A question:
    If I select RKRequestBackgroundPolicyContinue
    What happens before time expires (I think is about 10 minutes, but maybe you are downloading something large)? Is the request is cancelled, requeue again or restarted when app restarts?

    Thanks a lot.
    Are you sure you want to
    Your message goes here
    Processing…
  • Thanks for the useful slides.
    But in caching, when if I called 'fetchDataFromDataStore' method the app will crash and the reason: 'executeFetchRequest:error: A fetch request must have an entity'

    any idea why that happening since I did the same thing that you have done on 'RestKitDemo4' project.

    Mosab
    Are you sure you want to
    Your message goes here
    Processing…
  • where did you put these lines (slide 26) in your code?
    Are you sure you want to
    Your message goes here
    Processing…
  • You made me realize there's a simple call for the model, [XYZModel allObjects];

    That solves a lot.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

RestKit - From Zero to Hero RestKit - From Zero to Hero Presentation Transcript

  • Peter Friese, Zühlke EngineeringRestKitFrom 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 FlaO 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 clientRKClient *client = [RKClient clientWithBaseURL:@"http://github.org"];
  • Custom Headers// send this field with each request[client setValue: [[[UIDevice currentDevice] identifierForVendor] UUIDString] forHTTPHeaderField:@"X-UDID"];
  • Network Indicatorclient.requestQueue.showsNetworkActivityIndicatorWhenBusy = YES;
  • Network Indicatorclient.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 cachingclient.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 RelationshipsRKObjectMapping *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 RelationshipsRKObjectMapping *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 Objects1: Create new objectGithubIssue *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 MappingsRKObjectMapping *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 / BackendOnline 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 / BackendOnline - 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 / BackendReconnect 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 seedRKManagedObjectStore *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 Tableself.tableController = [[RKObjectManager sharedManager] fetchedResultsTableControllerForTableViewController:self];self.tableController.resourcePath = [self resourcePath];
  • RestKit UI - Networked Tableself.tableController = [[RKObjectManager sharedManager] fetchedResultsTableControllerForTableViewController:self];self.tableController.resourcePath = [self resourcePath];SortingNSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:@"createdAt" ascending:NO];self.tableController.sortDescriptors = [NSArray arrayWithObject:descriptor];
  • RestKit UI - Networked Tableself.tableController = [[RKObjectManager sharedManager] fetchedResultsTableControllerForTableViewController:self];self.tableController.resourcePath = [self resourcePath]; her nic e stuffOtself.tableController.autoRefreshFromNetwork = YES;self.tableController.pullToRefreshEnabled = YES;
  • RestKit UI - Cell MappingRKTableViewCellMapping *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