65
RestKit From Zero to Hero Peter Friese, Zühlke Engineering What’s that?!

RestKit - From Zero to Hero

Embed Size (px)

DESCRIPTION

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

Citation preview

Page 1: RestKit - From Zero to Hero

RestKitFrom Zero to Hero

Peter Friese, Zühlke Engineering

What’s that?!

Page 2: RestKit - From Zero to Hero

Integrating Twitter in Your iOS 5 Apps

@[email protected]/peterhttp://peterfriese.de

Peter Friese

Page 3: RestKit - From Zero to Hero

What we will cover today

1

2

3

Challenges

How can RestKit help?

Demos!

Page 4: RestKit - From Zero to Hero

Challenges...

Flaky Connectivity

Different Data Formats

Offline Data Access

Page 5: RestKit - From Zero to Hero

2

How can RestKit help?

Page 6: RestKit - From Zero to Hero

RestKit Features

Integrated HTTP StackPluggable ParserObject MappingCore Data IntegrationUI Integration

Page 7: RestKit - From Zero to Hero

Integrated HTTP Stack

Base URLsCustom HeadersNetwork IndicatorPerforming RequestsBackground ProcessingAuthentication

Request caching✔

Page 8: RestKit - From Zero to Hero

Base URL

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

Page 9: RestKit - From Zero to Hero

Custom Headers

// send this field with each request[client setValue:[[[UIDevice currentDevice] identifierForVendor] UUIDString]

forHTTPHeaderField:@"X-UDID"];

Page 10: RestKit - From Zero to Hero

Network Indicator

client.requestQueue.showsNetworkActivityIndicatorWhenBusy = YES;

Page 11: RestKit - From Zero to Hero

Network Indicator

client.requestQueue.showsNetworkActivityIndicatorWhenBusy = YES;

Page 12: RestKit - From Zero to Hero

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

Page 13: RestKit - From Zero to Hero

Requests with Blocks

- (IBAction)forkYouWithBlocks{ 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; } }]; }];}

Blocks FTW

Page 14: RestKit - From Zero to Hero

Background Processing[request setBackgroundPolicy:RKRequestBackgroundPolicyContinue];

// do nothingRKRequestBackgroundPolicyNone// cancel requestRKRequestBackgroundPolicyCancel

// continue until extra time expiresRKRequestBackgroundPolicyContinue// requeue upon app restart RKRequestBackgroundPolicyRequeue

Page 15: RestKit - From Zero to Hero

Authentication[clientsetAuthenticationType:RKRequestAuthenticationTypeHTTPBasic];

// disable authentication

RKRequestAuthenticationTypeNone

// NSURLConnection auto negotiation

RKRequestAuthenticationTypeHTTP

// HTTP Basic Auth

RKRequestAuthenticationTypeHTTPBasic

// OAuth 1.0

RKRequestAuthenticationTypeOAuth

// OAuth 2.0

RKRequestAuthenticationTypeOAuth2

Page 16: RestKit - From Zero to Hero

Request cachingclient.cachePolicy = RKRequestCachePolicyLoadIfOffline | RKRequestCachePolicyTimeout;

// don’t use request cacheRKRequestCachePolicyNone// use cache if offlineRKRequestCachePolicyLoadIfOffline // in case of an errorRKRequestCachePolicyLoadOnError// use ETagsRKRequestCachePolicyEtag// if we’ve got data storedRKRequestCachePolicyEnabled// in case of a timeoutRKRequestCachePolicyTimeout

Page 17: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser Object Mapping

JSON(new and cool)

XML(legacy)

Page 18: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser Object Mapping

JSON(new and cool)

XML(legacy)

Deprecated

Page 19: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser Object Mapping

Simple Object MappingMapping RelationshipsInverse MappingsSerialization Mappings

Page 20: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser Object Mapping

Page 21: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser Object Mapping

#->No Hashmaps

Page 22: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser 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

->

Page 23: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser 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

->

Page 24: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser 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

{id: 232107,name: "Peter Friese",location: "Hamburg",followers: 42,email: “[email protected],following: 36,

}

Page 25: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser 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

{id: 232107,name: "Peter Friese",location: "Hamburg",followers: 42,email: “[email protected],following: 36,

}

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

Page 26: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser 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

{id: 232107,name: "Peter Friese",location: "Hamburg",followers: 42,email: “[email protected],following: 36,

}

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

register mapping

for a class

Page 27: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser 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

{id: 232107,name: "Peter Friese",location: "Hamburg",followers: 42,email: “[email protected],following: 36,

}

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

register mapping

for a class

[objectMapping mapKeyPath:@"id" toAttribute:@"id"];[objectMapping mapKeyPath:@"name" toAttribute:@"name"];

Page 28: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser 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

{id: 232107,name: "Peter Friese",location: "Hamburg",followers: 42,email: “[email protected],following: 36,

}

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

register mapping

for a class

[objectMapping mapKeyPath:@"id" toAttribute:@"id"];[objectMapping mapKeyPath:@"name" toAttribute:@"name"]; configure mapping (KVC)

Page 29: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser GETting Objects

[[RKObjectManager sharedManager] loadObjectsAtResourcePath:

usingBlock:^(RKObjectLoader *loader) {

}];

Page 30: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser GETting Objects

[[RKObjectManager sharedManager] loadObjectsAtResourcePath:[NSString stringWithFormat:@"/users/%@", self.userName]

usingBlock:^(RKObjectLoader *loader) {

[loader setObjectMapping:self.mapping];

}];

Page 31: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser GETting Objects

[[RKObjectManager sharedManager] loadObjectsAtResourcePath:[NSString stringWithFormat:@"/users/%@", self.userName]

usingBlock:^(RKObjectLoader *loader) {

[loader setObjectMapping:self.mapping];

}];

resource path

mapping, as defined previously

Page 32: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser 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) {

}];}];

Page 33: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser 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) {

}];}];

happy case :-)

sad unhappy case :-(

Page 34: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser 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 :-(

Page 35: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser 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"];

}];}];

Page 36: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser 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"];

}];}];

heads up!

Page 37: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser 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"];

}];}];

Page 38: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser Mapping Relationships

->

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

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

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

[ { "number": 1347, "title": "Found a bug", "user": { "login": "octocat",

@interface GithubIssue : NSObject

@property NSNumber *number;@property NSString *title;@property GithubUser *user;

Page 39: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser Mapping Relationships

->

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

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

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

[ { "number": 1347, "title": "Found a bug", "user": { "login": "octocat",

@interface GithubIssue : NSObject

@property NSNumber *number;@property NSString *title;@property GithubUser *user;

Page 40: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser 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"];

Page 41: RestKit - From Zero to Hero

Integrated HTTP StackPluggable Parser POSTing Objects

->

GithubIssue *issue = [[GithubIssue alloc] init];

issue.repouser = repouser;issue.repo = repo;

[[RKObjectManager sharedManager] postObject:issue usingBlock:^(RKObjectLoader *loader){loader.onDidLoadResponse = ^(RKResponse *response) {[self dismissViewControllerAnimated:YES completion:nil];

}}];

1: Create new object

2: ProvideInfos for RestKit router:

3: POST object:

Page 42: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping Core Data Integration

Offline Data Access

Remember?

Page 43: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping Core Data Integration

Change Mapped Objects

Add a Core Data ModelRegister a Managed Object Store

Adjust Object Mappings

Adjust Object CreationFetch Data from DB / Backend

Page 44: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping Change Mapped Objects

@interface GithubUser : NSManagedObject

@interface GithubUser : NSObject

@synthesize id;@synthesize login;@synthesize name;@synthesize company;@synthesize location;@synthesize blog;@synthesize following;@synthesize followers;@synthesize email;

@dynamic id;@dynamic login;@dynamic name;@dynamic company;@dynamic location;@dynamic blog;@dynamic following;@dynamic followers;@dynamic email;

Header Header

Module Module

Page 45: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping Add a Core Data Model

Page 46: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping Add a Core Data Model

@interface GithubUser : NSObject

Page 47: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping Add a Core Data Model

Keep in mind:Assign respective

classes to managed objects!

@interface GithubUser : NSObject

Page 48: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping Register a Managed Object Store

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

// set up backing data storeobjectManager.objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:@"github.sqlite"];

Page 49: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping Adjust Object Mappings

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

RKManagedObjectMapping *userMapping = [RKManagedObjectMapping mappingForClass:[GithubUser class] inManagedObjectStore:objectStore];

Page 50: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping Adjust Object CreationGithubIssue *issue = [[GithubIssue alloc] init];

GithubIssue *issue = [GithubIssue object];

+ (id)object {

id object = [[self alloc]

initWithEntity:[self entity]

insertIntoManagedObjectContext:

[NSManagedObjectContext contextForCurrentThr

ead]];

return [object autorelease];

}

Page 51: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping Fetch Data from DB / Backend

if ([[RKObjectManager sharedManager] isOnline]) {[self fetchDataFromRemote];

}else {[self fetchDataFromDataStore];

}

Online of offline?

- (void)fetchDataFromDataStore {NSFetchRequest *request = [[[RKObjectManager sharedManager] mappingProvider] fetchRequestForResourcePath:self.resourcePath];

self.repos = [GithubRepo objectsWithFetchRequest:request];[self.tableView reloadData];

}

Offline - Fetch from DB

Page 52: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping Fetch Data from DB / Backend

- (void)fetchDataFromRemote {[[RKObjectManager sharedManager] loadObjectsAtResourcePath:[self resourcePath] usingBlock:^(RKObjectLoader *loader) {[loader setOnDidLoadObjects:^(NSArray *objects) {self.repos = objects;[self.tableView reloadData];

}];}];

}

Online - Fetch from Backend

Page 53: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping Fetch Data from DB / Backend

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

}}

}

Reconnect after offline

Page 54: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping Sync Managerhttps://github.com/RestKit/RestKit/pull/573

Page 55: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping Seeding your DB

[RKManagedObjectSeedergenerateSeedDatabaseWithObjectManager:objectManager fromFiles:@"repos.json", nil];

RKManagedObjectStore *objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:@"github.sqlite" usingSeedDatabaseName:@"seed_db.sqlite" managedObjectModel:nildelegate:nil];

Generate seed

Import seed

Page 56: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping Putting it All Together

Page 57: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping Putting it All Together

Wait a minute - can we do this simpler?

Page 58: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping RestKit UI

Static TablesNetworked TableForms

Page 59: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping RestKit UI - Networked Table

self.tableController = [[RKObjectManager sharedManager] fetchedResultsTableControllerForTableViewController:self];

self.tableController.resourcePath = [self resourcePath];

Page 60: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping RestKit UI - Networked Table

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

self.tableController.sortDescriptors = [NSArray arrayWithObject:descriptor];

Sorting

self.tableController = [[RKObjectManager sharedManager] fetchedResultsTableControllerForTableViewController:self];

self.tableController.resourcePath = [self resourcePath];

Page 61: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping RestKit UI - Networked Table

self.tableController.autoRefreshFromNetwork = YES;self.tableController.pullToRefreshEnabled = YES;

Other nice stuff

self.tableController = [[RKObjectManager sharedManager] fetchedResultsTableControllerForTableViewController:self];

self.tableController.resourcePath = [self resourcePath];

Page 62: RestKit - From Zero to Hero

Integrated HTTP StackPluggable ParserObject Mapping RestKit UI - Cell Mapping

RKTableViewCellMapping *cellMapping = [RKTableViewCellMapping cellMapping];

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

[cellMappingmapKeyPath:@"openIssues" toAttribute:@"detailTextLabel.text"];

[cellMappingsetAccessoryType:UITableViewCellAccessoryDisclosureIndicator];

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

Page 63: RestKit - From Zero to Hero

Thanks!

Remember that little spot

on the first slide?

http://www.slideshare.net/peterfriese

Page 64: RestKit - From Zero to Hero

Awesome Unicorn Coloring Slide