24
iOS for ERREST Paul Lynch @pauldlynch [email protected]

iOS for ERREST

Embed Size (px)

Citation preview

Page 2: iOS for ERREST

• We know WebObjects & ERREST

• The client problem

• Example ERREST/iOS architecture

• Some code specifics

• Some iOS client-server tips

• NOT how to write an iOS app - NO UITableView, etc

iOS for ERREST

Page 3: iOS for ERREST

App Store• Huddle

• b-london

• iWycombe

• SOE Status

• Comet

• Mobile Adventure Walks

Page 4: iOS for ERREST

Enterprise• DeLaRue

• Oetker

• Dorchester

• LifeFitness

• BidPresentation x 5

Page 5: iOS for ERREST

WebObjects

• Powerful system for server based development

• ERREST for RESTful servers

• Historically has used browsers for clients

Page 6: iOS for ERREST

Problem?

Page 7: iOS for ERREST

The Client

• HTML

• BUT <table>, Browser Wars, CSS

• Java Client

• BUT - Java - in the client

• Javascript/Single Page Applications

• BUT Javascript?, what framework?

Page 8: iOS for ERREST

The Client

• iOS

• iPhone for mass distribution

• iPad for Enterprise

• Objective C

• Xcode

• Foundation, UIKit

Page 9: iOS for ERREST

iOS Statistics (WWDC 2013)

• 600 million units sold

• iPad has 82% tablet market share

• iOS 6 is on 93% of all iOS devices

Page 10: iOS for ERREST

Objective C

• ARC

• properties

• blocks

• Grand Central Dispatch

• Xcode

• git

• OSS

Page 11: iOS for ERREST

• Huddle

• SaaS, Windows/IE oriented

• Comet *

• High street large enterprise, high volume shopping, ERREST

• Walks *

• “exergaming”, ERREST, Amazon EC2

• SOE Status

• game server updates

Examples

Page 12: iOS for ERREST

Comet Architecture

Marketing db

Reviews

WO dbXML

Linux, mySQL

Change Report

Mobile clients

Page 13: iOS for ERREST

Comet Database

Features: skunum, runId; xml/json held as strings

Category

SKU

Review WC7SKU

Client

Page 14: iOS for ERREST

REST API

• category - parent, children

• sku

• skudetail - contains full review and XML text

• brand - attribute of sku

Page 15: iOS for ERREST

Code Approaches

• CometAPI subclasses PLRestful

• per entity subclass (Sku, Category, etc)

• NSURLConnection

• ASIHTTPRequest (not maintained)

• AFNetworking (github)

• RESTKit - RestKit.org

Page 16: iOS for ERREST

PLRestful.h@class PLRestful;

typedef void (^PLRestfulAPICompletionBlock)(PLRestful *api, id object, int status, NSError *error);

@interface PLRestful : NSObject

@property (nonatomic, copy) NSString *endpoint;@property (nonatomic, copy) PLRestfulAPICompletionBlock completionBlock;@property (nonatomic, copy) NSString *username;@property (nonatomic, copy) NSString *password;

+ (NSString *)messageForStatus:(int)status;+ (BOOL)checkReachability:(NSURL *)url;+ (void)get:(NSString *)requestPath parameters:(NSDictionary *)parameters completionBlock:(PLRestfulAPICompletionBlock)completion;+ (void)post:(NSString *)requestPath content:(NSDictionary *)content completionBlock:(PLRestfulAPICompletionBlock)completion;

- (void)get:(NSString *)requestPath parameters:(NSDictionary *)parameters completionBlock:(PLRestfulAPICompletionBlock)completion;- (void)post:(NSString *)requestPath content:(NSDictionary *)content completionBlock:(PLRestfulAPICompletionBlock)completion;

@end

Page 17: iOS for ERREST

[skudetail viewDidLoad]; NSString *query = [NSString stringWithFormat:@"skudetail/%@.json", [sku valueForKey:@"skuNum"]];

[CometAPI get:query parameters:nil completionBlock:^(CometAPI *api, id object, int status, NSError *error) { if (error) { [PRPAlertView showWithTitle:@"Error" message:@"Unable to fetch product details" buttonTitle:@"Continue"]; } else { self.sku = object; [self.tableView reloadData]; } }];

Page 18: iOS for ERREST

CometAPI get- (void)get:(NSString *)requestString parameters:(NSDictionary *)parameters completionBlock:(CometAPICompletionBlock)completion {

NSURL *requestURL = [[NSURL URLWithString:endpoint] urlByAddingPath:requestString andParameters:parameters]; NSLog(@"get: '%@'", [requestURL absoluteString]); NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestURL]; if (userName && password && useBasicAuthentication) { NSString *authString = [[NSString stringWithFormat:@"%@:%@", userName, password] base64]; NSString *authHeader = [NSString stringWithFormat:@"Basic %@", authString]; [request setValue:authHeader forHTTPHeaderField:@"Authorization"];! ! } //[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];! [request setValue:@"application/json" forHTTPHeaderField:@"Accept"]; ...

Page 19: iOS for ERREST

CometAPI get

... self.completionBlock = completion; [[UIApplication sharedApplication] prp_pushNetworkActivity]; self.restQueue = [[NSOperationQueue alloc] init]; self.restQueue.name = @"Comet REST Queue"; [NSURLConnection sendAsynchronousRequest:request queue:self.restQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){ if (error) { NSLog(@"%s %@", __PRETTY_FUNCTION__, error); [self callCompletionBlockWithObject:nil error:error]; } else { if ([data length] == 0) { NSLog(@"no data"); [self callCompletionBlockWithObject:nil error:[NSError errorWithDomain:@"com.plsys.semaphore.CometAPI" code:1001 userInfo:nil]]; } else { NSError *error; id object = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error]; if (object) { [self callCompletionBlockWithObject:object error:nil]; } else { NSLog(@"received bad json: (%d) '%@'", [data length], [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); [self callCompletionBlockWithObject:nil error:[NSError errorWithDomain:@"com.plsys.semaphore.CometAPI" code:1002 userInfo:nil]]; } } } }];}

Page 20: iOS for ERREST

CometAPI Methods- (void)callCompletionBlockWithObject:(id)object error:(NSError *)error {

dispatch_async(dispatch_get_main_queue(), ^{ [[UIApplication sharedApplication] prp_popNetworkActivity]; self.completionBlock(self, object, error); });}

Page 21: iOS for ERREST

CometAPI Methods- (NSURL *)urlByAddingPath:(NSString *)path andParameters:(NSDictionary *)parameters; {

NSString *requestString = [[self absoluteString] stringByAppendingPathComponent:path]; if (parameters) { requestString = [requestString stringByAppendingString:@"?"]; BOOL first = YES; for (NSString *key in [parameters allKeys]) { if (!first) { requestString = [requestString stringByAppendingString:@"&"]; } requestString = [requestString stringByAppendingString:[NSString stringWithFormat:@"%@=%@", key, [[[parameters objectForKey:key] description] stringByAddingPercentEscapesUsingEncoding:kCFStringEncodingUTF8]]]; first = NO; } } return [NSURL URLWithString:requestString];}

Page 22: iOS for ERREST

Traps

• Connection reliability

• isn’t really “always on”

• Data cacheing

• performance?

• capacity?

• Update cacheing

• Reachability

Page 23: iOS for ERREST

Write more apps!