Post on 12-Oct-2014
description
transcript
Luis ReiLuisRei.com
me@luisrei.com@lmrei
DevelopingiOS
RESTApplications
• WHOAMI
• GLAZEDSOLUTIONS.COM
• HTML5 Mobile Apps - Friday 15h Main Stage
• It’s awesome: iPhone, iPad, iPod Touch
• Best Mobile App Dev Platform (by light years)
• Objective-C + Foundation + Cocoa
• Lots of potential users
• lots of potentially paying users
Why iOS
• Software architecture for distributed systems
• say web services/APIs
• Client-Server
• Works over HTTP & URI-based
• http://api.twitter.com/1/statuses/public_timeline.json
REST Quick Intro
• There’s always something you need in “the cloud”
• Data or processing power
• More true on mobile
• Universal: mobile, desktop, web clients
• It’s easy to implement server side ( at least the basic stuff)
• and everyone is doing it (twitter, github, amazon, google, ...)
• It’s easy to implement on the client
Why REST
REST/REST-Like APIs
iOS REST RecipeFunction Library I Use Currently iOS Boilerplate
HTTP Requests ASIHTTPRequest AFNetworking
JSON SBJson(AKA json-framework) JSONkit
Image Caching AFNetworking(I previously used HJCache) AFNetworking
Pull-To-Refresh PullToRefreshTableViewControllerby Leah Culver EGOTableViewPullToRefresh
HUD SVProgessHUD(I previously used DSActivityView) SVProgessHUD
• Am I connected to the internet?
• Wifi or Cellular?
Reachability(SystemConfiguration framework)
NSString * const SRVR = @"api.example.com";
-(BOOL)reachable{ Reachability *r = [Reachability reachabilityWithHostName:SRVR];
NetworkStatus internetStatus = [r currentReachabilityStatus];
if(internetStatus == NotReachable) { return NO; } return YES;}
NotReachableReachableViaWifi
ReachableViaWWAN
GET- (void)makeGetRequest{ NSURL *url = [NSURL URLWithString:@"http://api.example.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
NSError *error = [request error];
if (!error && [request responseStatusCode] == 200){
NSString *response = [request responseString];
//NSData *responseData = [request responseData]; }
Errors
else if(error)NSLog(@"request error: %@",[error localizedDescription]);
else if([request responseStatusCode] != 200)NSLog(@"server says: %@", [request responseString]);
}
•The app continues to execute
•UI continues to be responsive
•The request runs in the background
•Two (common) ways of doing it in iOS:
•Delegate
•Block
Asynchronous Requests
• The delegator object has a delegate property that points to the delegate object
• A delegate acts when its delegator encounters a certain event
• The delegate adopts a protocol
• We’ll need 2 methods: success & failure
Cocoa Delegate Pattern
Asynchronous GET- (void)makeGetRequest{NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; [request setDelegate:self];
[request startAsynchronous];}
// DELEGATE METHODS:- (void)requestFinished:(ASIHTTPRequest *)request{ NSString *responseString = [request responseString];}
- (void)requestFailed:(ASIHTTPRequest *)request{ NSError *error = [request error];}
Cocoa Blocks
• Ad hoc function body as an expression
• Carry their code & the data they need
• ideal for callbacks
• We’ll need 2 blocks: success & failure
Building Blocks- (void)makeGetRequest{ NSURL *url = [NSURL URLWithString:@"http://api.example.com"];
__block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setCompletionBlock:^{ NSString *responseString = [request responseString]; }];
[request setFailedBlock:^{ NSError *error = [request error]; }];
[request startAsynchronous];}
SVProgressHUD
#import "SVProgressHUD.h"
- (void)makeGetRequest{ NSURL *url = [NSURL URLWithString:@"http://api.example.com"]; ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[SVProgressHUD showWithStatus:@"Fetching data"]; [request startSynchronous];
if (![request error]) {" [SVProgressHUD dismissWithSuccess:@"Fetch Successful"]; ... } else {" [SVProgressHUD dismissWithError:@"Fetch Failed"];
... }}
Where to Load Data• viewDidLoad / viewWillAppear
• Make the asynchronous request
• Show HUD or other “loading” indicators
• LOADED = NO;
• Delegate
• LOADED = YES;
• Reload table
• Partial Load + Pagination
• Load more at the end of the table
PullToRefresh
#import "PullRefreshTableViewController.h"
@interface MyTableViewController : PullRefreshTableViewController
- (void)refresh { [self performSelector:@selector(add) withObject:nil afterDelay:2.0];}
- (void) add {...[self stopLoading];
}
.m
.h
Background Loading & Caching Images
#import "UIImageView+AFNetworking.h"
NSURL *imageURL = [NSURL URLWithString:@”http://example.com/picture.jpg”];UIImageView *image = [[UIImageView alloc] init];
[image setImageWithURL:imageURL];
Updating My Profile Picture
•Modify an existing record
•Authenticate
•Upload a file
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setRequestMethod:@"PUT"]; //REST modify using PUT
[request setPostFormat:ASIMultipartFormDataPostFormat];
// authentication[request setUsername:username];[request setPassword:password];
[request setFile:jpgPath forKey:@"image"];"
[request startSynchronous];
POST & DELETE
[request setRequestMethod:@"POST"];
[request setRequestMethod:@"DELETE"];
I JSON (because it’s not XML)
JSON OBJECTIVE-C/FOUNDATION
Object NSDictionary
Array NSArray
String NSString
Number NSNumber
Boolean NSNumber (0 or 1)
1. Download a JSON string (via an http request)
2.Convert it to native data structures (parsing)
3.Use the native data structures
Parsing
[request startSynchronous];...SBJsonParser *prsr = [[[SBJsonParser alloc] init] autorelease];
// objectNSDictionary *data = [prsr objectWithString:[request responseString]];
// or ArrayNSArray *data = [parsr objectWithString:[request responseString]];
INCEPTION
[{[{}]}]An array of
objects with an array of objects
[ { "name": "object1", "sub": [ { "name": "subobject1" }, { "name": "subobject2" } ] }, ]
or rather JCEPTION
NSArray *jArray = [prsr objectWithString:data];
NSDictionary *obj1 = [jArray objectAtIndex:0];
NSString *obj1Name = [obj1 objectForKey:@”name”];
NSArray *obj1SubArray = [obj1 objectForKey:@”sub”];
NSDictionary *subObj1 = [obj1SubArray objectAtIndex:0];
NSNumber *subObj1Val = [subObj1 objectForKey@”value”];
[ { "name": "object1", "sub": [ { "name": "subobject1" }, { "value": 1 } ] },]
...[[[prsr objectWithSring:data] objectAtIndex:0] objectForKey:@”sub]...