restkit - from zero to hero

Post on 15-May-2015

17.828 Views

Category:

Technology

9 Downloads

Preview:

Click to see full reader

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

RestKitFrom Zero to Hero

Peter Friese, Zühlke Engineering

What’s that?!

Integrating Twitter in Your iOS 5 Apps

@peterfriesepeter.friese@zuehlke.comxing.to/peterhttp://peterfriese.de

Peter Friese

What we will cover today

1

2

3

Challenges

How can RestKit help?

Demos!

Challenges...

Flaky Connectivity

Different Data Formats

Offline Data Access

2

How can RestKit help?

RestKit Features

Integrated HTTP StackPluggable ParserObject MappingCore Data IntegrationUI Integration

Integrated HTTP Stack

Base URLsCustom HeadersNetwork IndicatorPerforming RequestsBackground ProcessingAuthentication

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 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{ 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

Background Processing[request setBackgroundPolicy:RKRequestBackgroundPolicyContinue];

// do nothingRKRequestBackgroundPolicyNone// cancel requestRKRequestBackgroundPolicyCancel

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

Authentication[clientsetAuthenticationType:RKRequestAuthenticationTypeHTTPBasic];

// disable authentication

RKRequestAuthenticationTypeNone

// NSURLConnection auto negotiation

RKRequestAuthenticationTypeHTTP

// HTTP Basic Auth

RKRequestAuthenticationTypeHTTPBasic

// OAuth 1.0

RKRequestAuthenticationTypeOAuth

// OAuth 2.0

RKRequestAuthenticationTypeOAuth2

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

Integrated HTTP StackPluggable Parser Object Mapping

JSON(new and cool)

XML(legacy)

Integrated HTTP StackPluggable Parser Object Mapping

JSON(new and cool)

XML(legacy)

Deprecated

Integrated HTTP StackPluggable Parser Object Mapping

Simple Object MappingMapping RelationshipsInverse MappingsSerialization Mappings

Integrated HTTP StackPluggable Parser Object Mapping

Integrated HTTP StackPluggable Parser Object Mapping

#->No Hashmaps

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

->

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

->

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: “peter@peterfriese.de,following: 36,

}

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: “peter@peterfriese.de,following: 36,

}

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

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: “peter@peterfriese.de,following: 36,

}

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

register mapping

for a class

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: “peter@peterfriese.de,following: 36,

}

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

register mapping

for a class

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

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: “peter@peterfriese.de,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)

Integrated HTTP StackPluggable Parser GETting Objects

[[RKObjectManager sharedManager] loadObjectsAtResourcePath:

usingBlock:^(RKObjectLoader *loader) {

}];

Integrated HTTP StackPluggable Parser GETting Objects

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

usingBlock:^(RKObjectLoader *loader) {

[loader setObjectMapping:self.mapping];

}];

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

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) {

}];}];

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 :-(

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 :-(

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

}];}];

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!

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

}];}];

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;

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;

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

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:

Integrated HTTP StackPluggable ParserObject Mapping Core Data Integration

Offline Data Access

Remember?

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

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

Integrated HTTP StackPluggable ParserObject Mapping Add a Core Data Model

Integrated HTTP StackPluggable ParserObject Mapping Add a Core Data Model

@interface GithubUser : NSObject

Integrated HTTP StackPluggable ParserObject Mapping Add a Core Data Model

Keep in mind:Assign respective

classes to managed objects!

@interface GithubUser : NSObject

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

Integrated HTTP StackPluggable ParserObject Mapping Adjust Object Mappings

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

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

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

}

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

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

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

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

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

Integrated HTTP StackPluggable ParserObject Mapping Putting it All Together

Integrated HTTP StackPluggable ParserObject Mapping Putting it All Together

Wait a minute - can we do this simpler?

Integrated HTTP StackPluggable ParserObject Mapping RestKit UI

Static TablesNetworked TableForms

Integrated HTTP StackPluggable ParserObject Mapping RestKit UI - Networked Table

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

self.tableController.resourcePath = [self resourcePath];

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

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

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

Thanks!

Remember that little spot

on the first slide?

http://www.slideshare.net/peterfriese

Awesome Unicorn Coloring Slide

top related