restkit - from zero to hero

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

Upload: peter-friese

Post on 15-May-2015

17.828 views

Category:

Technology


9 download

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

TRANSCRIPT

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