Introduction to RestKit Blake Watters

Wednesday, September 14, 11

Technology Overview • Integrated HTTP stack – NSURLConnection based – Simplifies common tasks

• Object Mapping – Build domain objects for REST resources

• Core Data Integration – Active Record Pattern Implementation – Extends Object Mapping

• Table UI Toolkit – Map objects to table cells Wednesday, September 14, 11

2

Project Overview • Apache Licensed • Built on Core Apple Technologies

• Large, active community • Over 1100 Github Watchers

• Production Ready

• ~200 Forks

• Well supported

• 500+ Mailing List Members

• Fast Moving

3 Wednesday, September 14, 11

Network Layer

4 Wednesday, September 14, 11

Initializing RKClient - (void)initRKClient { ! // Initialize with a Base URL ! RKClient* client = [RKClient clientWithBaseURL:@"http://restkit.org"]; ! ! // Setup HTTP AUTH ! client.username = @"restkit"; ! client.password = @"rocks"; ! ! // Set an app-wide API key HTTP header ! [client setValue:@"123456" forHTTPHeaderField:@"X-RESTKIT-API-KEY"]; ! ! // The first initialized RKClient becomes ! // the sharedClient instance ! [[RKClient sharedClient] isNetworkAvailable]; }

5 Wednesday, September 14, 11

Sending Requests - (void)sendRequest { ! // Send an HTTP GET request to 'http://restkit.org/contacts' ! [[RKClient sharedClient] get:@"/contacts" delegate:self]; } // RKRequestDelegate methods - (void)request:(RKRequest *)request didLoadResponse:(RKResponse *)response { ! RKLogInfo(@"Yay! We Got a response"); } - (void)request:(RKRequest*)request didFailLoadWithError:(NSError *)error { ! RKLogInfo(@"Oh no! We encountered an error: %@", [error localizedDescription]); }

6 Wednesday, September 14, 11

Processing Responses - (void)sendRequest { ! // Send an HTTP GET request to 'http://restkit.org/contacts' ! [[RKClient sharedClient] get:@"/contacts" delegate:self]; } - (void)request:(RKRequest *)request didLoadResponse:(RKResponse *)response { ! RKLogInfo(@"Request Headers: %@", [response allHeaderFields]); ! RKLogInfo(@"Cookies: %@", [response cookies]) ! ! if ([response isSuccessful]) { ! ! // Response status was 200..299 ! ! if ([response isCreated] && [response isJSON]) { ! ! ! // Looks like we have a 201 response of type 'application/json' ! ! ! RKLogInfo(@"The JSON is %@", [response bodyAsJSON]); ! ! } ! } else if ([response isError]) { ! ! // Response status was either 400..499 or 500..599 ! ! RKLogInfo(@"Ouch! We have an HTTP error. Status Code description: %@", [response localizedStatusCodeString]); ! } }

7 Wednesday, September 14, 11

Requests with Parameters - (void)sendRequestWithParams { ! // Simple params ! NSDictionary* paramsDictionary = [NSDictionary dictionaryWithObjectsAndKeys: ! ! ! ! ! ! ! ! ! @"Joe Blow", @"name", ! ! ! ! ! ! ! ! ! @"Acme, Inc", @"company", nil]; ! [[RKClient sharedClient] post:@"/contacts" params:paramsDictionary delegate:self]; ! ! // Multi-part params via RKParams! ! RKParams* params = [RKParams paramsWithDictionary:paramsDictionary]; ! NSData* imageData = UIImagePNGRepresentation([UIImage imageNamed:@"picture.jpg"]); ! [params setData:imageData MIMEType:@"image/png" forParam:@"photo"]; ! [params setFile:@"bio.txt" forParam:@"attachment"]; ! [[RKClient sharedClient] post:@"/contacts" params:params delegate:self]; }

8 Wednesday, September 14, 11

Reachability - (void)demoReachability { ! // Check if the network is available ! [[RKClient sharedClient] isNetworkAvailable]; ! ! // Register for changes in network availability ! NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; ! [center addObserver:self selector:@selector(reachabilityDidChange:) name:RKReachabilityStateChangedNotification object:nil]; } - (void)reachabilityDidChange:(NSNotification *)notification { ! RKReachabilityObserver* observer = (RKReachabilityObserver *) [notification object]; ! RKReachabilityNetworkStatus status = [observer networkStatus]; ! if (RKReachabilityNotReachable == status) { ! ! RKLogInfo(@"No network access!"); ! } else if (RKReachabilityReachableViaWiFi == status) { ! ! RKLogInfo(@"Online via WiFi!"); ! } else if (RKReachabilityReachableViaWWAN == status) { ! ! RKLogInfo(@"Online via Edge or 3G!"); ! } }

Wednesday, September 14, 11

9

Request Queue - (IBAction)queueRequests { RKRequestQueue* queue = [RKRequestQueue new]; queue.delegate = self; queue.concurrentRequestsLimit = 1; queue.showsNetworkActivityIndicatorWhenBusy = YES; // Queue up 4 requests [queue addRequest:[RKRequest restkit.org"] delegate:nil]]; [queue addRequest:[RKRequest restkit.org"] delegate:nil]]; [queue addRequest:[RKRequest restkit.org"] delegate:nil]]; [queue addRequest:[RKRequest restkit.org"] delegate:nil]];

requestWithURL:[NSURL URLWithString:@"http:// requestWithURL:[NSURL URLWithString:@"http:// requestWithURL:[NSURL URLWithString:@"http:// requestWithURL:[NSURL URLWithString:@"http://

// Start processing! [queue start]; [queue cancelAllRequests]; }

10 Wednesday, September 14, 11

Object Mapping

11 Wednesday, September 14, 11

Initializing the Object Manager - (void)initObjectManager { ! RKObjectManager *manager = [RKObjectManager objectManagerWithBaseURL:@"http:// restkit.org"]; // Ask for & generate JSON manager.acceptMIMEType = RKMIMETypeJSON; manager.serializationMIMEType = RKMIMETypeJSON; ! // Object manager has a client [manager.client setValue:@"123456" forHTTPHeaderField:@"X-RESTKIT-API-KEY"]; }

12 Wednesday, September 14, 11

Modeling a RESTful Service /contacts [{        'contact':  {                'id':  1234,                'name':  'Blake  Wa8ers',                'email':  '[email protected]',                'company':  'GateGuru',  'birth_date':  '11/27/1982'        } }, {        'contact':  {                'id':  3456,                'name':  'John  Doe',                'email':  '[email protected]',                'company':  'Acme,  Inc'        } }] Wednesday, September 14, 11

@interface Contact @interface  Contact  :  NSObject    @property  (retain)  NSNumber*  contactID;    @property  (retain)  NSString*  name;    @property  (retain)  NSString*  email;    @property  (retain)  NSString*  company;    @property  (retain)  NSDate*  birthDate; @end

13

Configuring an Object Mapping - (void)setupContactMapping { RKObjectMapping *contactMapping = [RKObjectMapping mappingForClass:[Contact class]]; [contactMapping mapKeyPath:@"id" toAttribute:@"contactID"]; [contactMapping mapKeyPath:@"birth_date" toAttribute:@"birthDate"]; [contactMapping mapAttributes:@"name", @"email", @"company", nil]; NSDateFormatter *dateFormatter = [NSDateFormatter new]; [dateFormatter setDateFormat:@"MM/dd/yyyy"]; // 11/27/1982 dateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; contactMapping.dateFormatters = [NSArray arrayWithObject:dateFormatter]; [[RKObjectManager sharedManager].mappingProvider setMapping:contactMapping forKeyPath:@"contact"]; }

14 Wednesday, September 14, 11

Loading Remote Objects - (void)loadRemoteObjects { ! [[RKObjectManager sharedManager] loadObjectsAtResourcePath:@"/contacts" delegate:self]; } - (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects { ! if ([objectLoader wasSentToResourcePath:@"/contacts"]) { ! ! // Introspect the resource path ! ! NSLog(@"Nice! We loaded the following contacts: %@", objects); ! } } - (void)objectLoader:(RKObjectLoader *)objectLoader didFailWithError:(NSError *)error { ! // Note that failures here can be at the _application_ level in addition to transport ! NSLog(@"Rats! Failed to load objects: %@", [error localizedDescription]); }

15 Wednesday, September 14, 11

What just happened? • RKObjectManager configured to map ‘contact’ dictionaries to Contact class • Asynchronous GET sent to ‘/contacts’ via RKObjectLoader • 200 response returned, with JSON body • RKObjectMapper parsed payload and mapped JSON data to Contact objects • Callback invoked with array of Contacts 16 Wednesday, September 14, 11

Configuring the Router - (void)configureRouter { ! RKObjectRouter* router = [RKObjectManager sharedManager].router; ! ! // Configure a default route ! [router routeClass:[Contact class] toResourcePath:@"/contacts/:contactID"]; ! [router routeClass:[Contact class] toResourcePath:@"/contacts" forMethod:RKRequestMethodPOST]; }

17 Wednesday, September 14, 11

RESTful Object Manipulation // Create a new Contact - (void)createObject { ! Contact* contact = [Contact new]; ! contact.name = @"RestKit User"; ! contact.email = @"[email protected]"; ! ! // POST to /contacts ! [[RKObjectManager sharedManager] postObject:contact delegate:self]; } // Edit Contact with ID 12345 - (void)editObject { ! Contact* contact = [Contact new]; ! contact.contactID = [NSNumber numberWithInt:12345]; ! contact.name = @"New Name"; ! ! // POST to /contacts/12345 ! [[RKObjectManager sharedManager] putObject:contact delegate:self]; } // Delete Contact with ID 321 - (void)deleteObject { ! Contact* contact = [Contact new]; ! contact.contactID = [NSNumber numberWithInt:321]; ! ! // DELETE to /contacts/321 ! [[RKObjectManager sharedManager] deleteObject:contact delegate:self];! }

Wednesday, September 14, 11

18

Core Data

19 Wednesday, September 14, 11

Configuring RKManagedObjectStore - (void)configureObjectStore { // Initialize the RestKit Object Manager RKObjectManager* objectManager = [RKObjectManager objectManagerWithBaseURL:@"http://restkit.org"]; ! // Initialize object store // We are using the Core Data support, so we have initialized a managed object store backed // with a SQLite database. objectManager.objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:@"Contacts.sqlite"]; }

20 Wednesday, September 14, 11

Making Contact Persistent #import @interface Contact : NSManagedObject @end @implementation Contact @dynamic @dynamic @dynamic @dynamic

name; email; company; contactID;

@end - (void)coreDataMapping { RKManagedObjectMapping *mapping = [RKManagedObjectMapping mappingForClass: [Contact class] inManagedObjectStore:store]; mapping.primaryKeyAttribute = @"contactID"; }

21 Wednesday, September 14, 11

Working with Core Data - (void)workWithCoreData { ! // Get all the Contacts ! NSArray* contacts = [Contact findAll]; ! ! // Count the Contacts ! NSError* error = nil; ! NSUInteger count = [Contact count:&error]; ! ! // Find Contact by primary key ! NSNumber* contactID = [NSNumber numberWithInt:12345]; ! Article* somebody = [Contact findFirstByAttribute:@"contactID" withValue:contactID]; ! ! // Find Contacts with criteria ! NSPredicate* predicate = [NSPredicate predicateWithFormat:@"name contains[cd] 'restkit'"]; ! NSArray* matches = [Contact findAllWithPredicate:predicate]; ! ! // Find first 10 Contacts, sorted by name ! NSSortDescriptor* sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]; ! NSFetchRequest* fetchRequest = [Contact fetchRequest]; ! [fetchRequest setFetchLimit:10]; ! [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]]; ! NSArray* sortedContacts = [Contact executeFetchRequest:fetchRequest]; }

Wednesday, September 14, 11

22

Database Seeding // This is typically configured as a secondary target on your project // Dump your seed data out of your backend system in JSON format // Add to the project as resources // Run the secondary target in the Simulator - (void)seedTheDatabase { ! // Setup the object manager ! RKObjectManager* objectManager = [RKObjectManager objectManagerWithBaseURL:@"http:// restkit.org"]; ! objectManager.objectStore = [RKManagedObjectStore objectManagerWithStoreFilename:@"ContactsSeed.sqlite"]; ! ! // Load all the data from the file contacts.json into a seed database ! // The seeder will print instructions for how to copy the data to your app ! RKObjectSeeder* seeder = [RKObjectSeeder objectSeederWithObjectManager:objectManager]; ! [seeder seedObjectsFromFiles:@"contacts.json", nil]; ! [seeder finalizeSeedingAndExit]; }

23 Wednesday, September 14, 11

RestKit UI

24 Wednesday, September 14, 11

Static Table - (void)loadStaticTable { RKTableController *tableController = [RKTableController tableControllerWithTableView:self.tableView]; NSArray* tableItems = [NSArray arrayWithObjects: [RKTableItem tableItemWithText:@"User" URL:@"gg://user"], [RKTableItem tableItemWithText:@"Connect" URL:@"gg://user/connect"], [RKTableItem tableItemWithText:@"Bookmarks" URL:@"gg://user/bookmarks"], [RKTableItem tableItemWithText:@"Reviews & Tips" URL:@"gg://user/reviews"], [RKTableItem tableItemWithText:@"Scores" URL:@"gg://user/scores"], nil]; // Load the table view [self.tableController loadTableItems:tableItems withMappingBlock:^(RKTableViewCellMapping* cellMapping) { cellMapping.accessoryType = UITableViewCellAccessoryDisclosureIndicator; cellMapping.onSelectCellForObjectAtIndexPath = ^(UITableViewCell* cell, id object, NSIndexPath* indexPath) { TTOpenURL([object valueForKey:@"URL"]); }; }]; }

25 Wednesday, September 14, 11

26 Wednesday, September 14, 11

Network Table - (void)loadTableView { // Setup the Table View Model self.tableController = [RKTableController tableControllerWithTableView:self.tableView]; self.tableController.delegate = self; self.tableController.imageForEmpty = [UIImage imageNamed:@"no_high_flyers.png"]; self.tableController.imageForOffline = [UIImage imageNamed:@"offline.png"]; [self.tableController mapObjectsWithClass:[GGHighFlyer class] toTableCellsWithMapping: [RKTableViewCellMapping cellMappingWithBlock:^(RKTableViewCellMapping* cellMapping) { cellMapping.cellClass = [GGHighFlyerTableViewCell class]; cellMapping.selectionStyle = UITableViewCellSelectionStyleNone; cellMapping.rowHeight = 44; [cellMapping mapAttributes:@"points", @"login", nil]; cellMapping.onCellWillAppearForObjectAtIndexPath = ^(UITableViewCell* cell, id object, NSIndexPath* indexPath) { GGHighFlyerTableViewCell* highFlyerCell = (GGHighFlyerTableViewCell*) cell; highFlyerCell.captain = (indexPath.row == 0); highFlyerCell.rank = indexPath.row + 1; }; }]]; NSString* resourcePath = [NSString stringWithFormat:@"/airports/%@/high_flyers.json", [_airport airportId]]; NSString* resourcePathWithQueryString = [self addQueryStringToResourcePath:resourcePath]; [self.tableController loadTableFromResourcePath:resourcePathWithQueryString]; }

27 Wednesday, September 14, 11

28 Wednesday, September 14, 11

Building a Form - (void)changePasswordForm { GGUser *user = [GGUser user]; RKForm *form = [RKForm formForObject:user withBlock:^(RKForm *form) { [form addRowForAttribute:@"password" withControlType:RKFormControlTypeTextFieldSecure block:^(RKControlTableItem *tableItem) { tableItem.textField.placeholder = @"New Password"; tableItem.textField.returnKeyType = UIReturnKeyDone; tableItem.textField.keyboardAppearance = UIKeyboardAppearanceAlert; }]; form.onSubmit = ^{ NSError* error = nil; GGUser *user = (GGUser *) form.object; if (! [[GGUser user] changePassword:user.password error:&error]) { GGAlertWithTitleAndMessage(@"Invalid Password", [error localizedDescription]); } }; }]; [self.tableController loadForm:form]; }

29 Wednesday, September 14, 11

30 Wednesday, September 14, 11

Thank You! http://restkit.org/ http://twitter.com/restkit http://github.com/RestKit/RestKit Wednesday, September 14, 11

Introduction to RestKit Blake Watters - GitHub

Sep 14, 2011 - Multi-part params via RKParams. RKParams* params = [RKParams paramsWithDictionary:paramsDictionary];. NSData* imageData .... This is typically configured as a secondary target on your project. // Dump your seed data out of your backend system in JSON format. // Add to the project as resources.

8MB Sizes 0 Downloads 368 Views

Recommend Documents

Blake Seers – Curriculum Vitae - GitHub
2012–2017 Doctor of Philosophy (Statistics and Marine Science), University of Auckland,. Auckland. 2010–2011 Master of Science (Statistics), University of Auckland, Auckland. Graduated with second class honours, first division. 2009–2010 Postgr

Introduction to Algorithms - GitHub
Each cut is free. The management of Serling ..... scalar multiplications to compute the 100 50 matrix product A2A3, plus another. 10 100 50 D 50,000 scalar ..... Optimal substructure varies across problem domains in two ways: 1. how many ...

Introduction to R - GitHub
Nov 30, 2015 - 6 Next steps ... equals, ==, for equality comparison. .... invoked with some number of positional arguments, which are always given, plus some ...

Introduction To DCA - GitHub
Maximum-Entropy Probability Model. Joint & Conditional Entropy. Joint & Conditional Entropy. • Joint Entropy: H(X,Y ). • Conditional Entropy: H(Y |X). H(X,Y ) ...

Introduction to phylogenetics using - GitHub
Oct 6, 2016 - 2.2 Building trees . ... Limitations: no model comparison (can't test for the 'best' tree, or the 'best' model of evolution); may be .... more efficient data reduction can be achieved using the bit-level coding of polymorphic sites ....

Introduction to Fluid Simulation - GitHub
upon the notes for a Siggraph course on Fluid Simulation[Bridson. 2007]. I also used .... “At each time step all the fluid properties are moved by the flow field u.

122COM: Introduction to C++ - GitHub
All students are expected to learn some C++. .... Going to be learning C++ (approved. ). ..... Computer Science - C++ provides direct memory access, allowing.

Introduction to NumPy arrays - GitHub
www.scipy-lectures.org. Python. Matplotlib. SciKits. Numpy. SciPy. IPython. IP[y]:. Cython. 2015 ..... numbers and determine the fraction of pairs which has ... origin as a function of time. 3. Plot the variance of the trajectories as a function of t

An Introduction to BigQuery - GitHub
The ISB-CGC platform includes an interactive Web App, over a Petabyte of TCGA data in Google Genomics and Cloud Storage, and tutorials and code ...

Introduction to NumPy arrays - GitHub
we want our code to run fast. ▷ we want support for linear algebra ... 7. 8 a[0:5] a[5:8]. ▷ if step=1. ▷ slice contains the elements start to stop-1 .... Indexing and slicing in higher dimensions. 0. 8. 16. 24. 32. 1. 9. 17. 25. 33. 2. 10. 18.

Introduction to Framework One - GitHub
Introduction to Framework One [email protected] ... Event Management, Logging, Caching, . ... Extend framework.cfc in your Application.cfc. 3. Done. (or in the ... All controllers are passed the argument rc containing the request.context, and all v

introduction - GitHub
warehouse to assemble himself. Pain-staking and time-consuming... almost like building your own base container images. This piggy purchased high- quality ...

Introduction - GitHub
software to automate routine labor, understand speech or images, make diagnoses ..... Shaded boxes indicate components that are able to learn from data. 10 ...... is now used by many top technology companies including Google, Microsoft,.

Introduction - GitHub
data. There are many ways to learn functions, but one particularly elegant way is ... data helps to guard against over-fitting. .... Gaussian processes for big data.

Introduction - GitHub
For the case that your PDF viewer does not support this, there is a list of all the descriptions on ...... 10. Other Formats. 10.1. AMS-TEX. AMS-TEX2.0. A macro package provided by the American .... A TeX Live port for Android OS. Based on ...

Introduction - GitHub
them each year. In an aggregate travel demand model, this would be represented as 100/365.25 = 0.2737851 trucks per day. In the simulation by contrast, this is represented as ... based on the distance traveled (Table 3.3). 2FAF3 Freight Traffic Analy

Course: Introduction to Intelligent Transportation Systems - GitHub
... Introduction to Intelligent Transportation Systems. University of Tartu, Institute of Computer Science. Project: Automatic Plate Number. Recognition (APNR).

Introduction to REST and RestHUB - GitHub
2. RestHUBанаRESTful API for Oracle DB querying. 2.1. Overview. RestHub was designed .... For example we want to create a simple HTML + Javascript page.

A Beginner's Introduction to CoffeeKup - GitHub
the buffer, then calls the title function which adds it s own HTML to the buffer, and ... Now it is starting to look like real HTML you d find on an ugly web page. 2 ...

Introduction to Scientific Computing in Python - GitHub
Apr 16, 2016 - 1 Introduction to scientific computing with Python ...... Support for multiple parallel back-end processes, that can run on computing clusters or cloud services .... system, file I/O, string management, network communication, and ...

Glow Introduction - GitHub
Architecture: Data Flow. 1. Outputs of tasks are saved by local agents. 2. Driver remembers all data locations. 3. Inputs of next group of tasks are pulled from the ...

Introduction to Handibot Software and Handibot Apps I. Hello ... - GitHub
describing the new “FabMo” software platform that runs the tools. ... as a methodology because we believe it is an effective way for small companies, ..... Page 10 ...

An introduction to pplex and the Simplex Method - GitHub
Nov 16, 2012 - include: simple command line interface, visualization (two variables), file input in ... program is brought into the following form, called a dictionary in [2]: ζ. = x + ..... [7] http://campuscgi.princeton.edu/~rvdb/JAVA/pivot/simple

OWL 2 Profiles: An Introduction to Lightweight Ontology ... - GitHub
The three ontology language standards are sublanguages of OWL DL that are restricted in ways ... expert knowledge in a formal way, and as a logical language, it can be used to draw conclusions from ..... We call such features syntactic sugar.