SlideShare a Scribd company logo
iOS REST Client
Paul Lynch
@pauldlynch, paul@plsys.co.uk
• Architecture of iOS apps
• Comet Architecture
• Model Implementation
• Controller Implementation
• Other iOS Concepts
iOS REST Client
Architecture of iOS apps
• MVC - Model/View/Controller
• Objective C
• Foundation
• UIKit - UIApplication, UIViewController, UIView, UIControl
Foundation
• NSArray, NSDictionary, NSSet
• NSValue
• NSPredicate
UIKit - UIApplication
• UIApplication
• status bar
• window
• orientation
• AppDelegate
applicationDidFinishLaunchingWithOptions:
notifications - UIApplicationWillEnterForegroundNotification,
UIApplicationDidEnterBackgroundNotification
UIView
• animations
• gestures
View Controllers
• - (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle
• navigationController, tabBarController
• rotation, transitions
• subclasses - e.g. UITableViewController
TableViews
• UITableViewController
• UITableView
• data source
• delegate
• UITableViewCell
Table view data source
@protocol UITableViewDataSource<NSObject>
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section;
...
@end
@interface NSIndexPath (UITableView)
+ (NSIndexPath *)indexPathForRow:(NSInteger)row inSection:(NSInteger)section;
@property(nonatomic,readonly) NSInteger section;
@property(nonatomic,readonly) NSInteger row;
@end
Table view delegate
@protocol UITableViewDelegate<NSObject, UIScrollViewDelegate>
...
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath;
...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
...
@end
Comet Architecture
Comet Architecture
Marketing
db
Reviews
WO db
XML
Linux, mySQL
Change
Report
Mobile
clients
Comet Database
Features: skunum, runId; xml/json held as strings
Category
SKU
Review WC7SKU
Client
REST API
• category - parent, children
• sku
• skudetail - contains full review and XML text
• brand - attribute of sku
ERREST Routes
	 	 routeRequestHandler.addRoute(new ERXRoute(Sku.ENTITY_NAME, "/sku", ERXRoute.Method.Options, SkuController.class,
"options"));
	 	 routeRequestHandler.addRoute(new ERXRoute(Sku.ENTITY_NAME, "/sku", ERXRoute.Method.Head, SkuController.class, "head"));
	 	 routeRequestHandler.addRoute(new ERXRoute(Sku.ENTITY_NAME, "/sku", ERXRoute.Method.All, SkuController.class, "index"));
	 	 // MS: this only works with numeric ids
	 	 routeRequestHandler.addRoute(new ERXRoute(Sku.ENTITY_NAME, "/sku/{action:identifier}", ERXRoute.Method.Get, SkuController.class));
	 	 routeRequestHandler.addRoute(new ERXRoute(Sku.ENTITY_NAME, "/sku/{sku:Sku}", ERXRoute.Method.Get, SkuController.class, "show"));
	 	 routeRequestHandler.addRoute(new ERXRoute(Sku.ENTITY_NAME, "/sku/{sku:Sku}/{action:identifier}", ERXRoute.Method.All,
SkuController.class));
plus Category, Brand, Skudetail
Model Implementation
• PLRestful
• CometAPI
• Sku (etc)
PLRestful
typedef void (^PLRestfulAPICompletionBlock)(PLRestful *api, id object, NSInteger 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;
@property (nonatomic, assign) BOOL useBasicAuthentication;
+ (NSString *)messageForStatus:(NSInteger)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
PLRestful - get
- (void)get:(NSString *)requestString parameters:(NSDictionary *)parameters completionBlock:
(PLRestfulAPICompletionBlock)completion {
NSURL *requestURL = [[NSURL URLWithString:endpoint] urlByAddingPath:requestString parameters:parameters];
NSLog(@"get: '%@'", [requestURL absoluteString]);
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestURL];
[request setHTTPMethod:@"GET"];
[self handleRequest:request completion:(PLRestfulAPICompletionBlock)completion];
}
PLRestful - post
- (void)post:(NSString *)requestString content:(NSDictionary *)content completionBlock:(PLRestfulAPICompletionBlock)completion {
NSURL *requestURL = [[NSURL URLWithString:endpoint] urlByAddingPath:requestString parameters:nil];
NSLog(@"post: '%@'", [requestURL absoluteString]);
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestURL];
[request setHTTPMethod:@"POST"];
NSError *error = nil;
request.HTTPBody = [NSJSONSerialization dataWithJSONObject:content options:0 error:&error];
if (error) {
NSLog(@"json generation failed: %@", error);
[self callCompletionBlockWithObject:nil status:0 error:[NSError errorWithDomain:@"com.plsys.semaphore.CometAPI" code:1003 userInfo:nil]];
return;
}
[self handleRequest:request completion:completion];
}
Controller Implementation
• SkuController
• subclass of UITableViewController
SkuController - data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [skus count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *sku = [skus objectAtIndex:indexPath.row];
static NSString *CellIdentifier = @"SkuCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}
// Configure the cell...
cell.textLabel.text = [[sku valueForKey:@"productName"] pl_stringByStrippingHTML];
cell.detailTextLabel.text = [sku valueForKey:@"skuNum"];
id image = [images objectAtIndex:indexPath.row];
if ([image isKindOfClass:[UIImage class]]) {
cell.imageView.image = image;
}
return cell;
}
SkuController - tv delegate
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
NSDictionary *sku = [skus objectAtIndex:indexPath.row];
NSString *skuNum = [[sku valueForKey:@"skuNum"] copy];
NSLog(@"tapped: %@", skuNum);
SkuDetail *view = [[SkuDetail alloc] initWithStyle:UITableViewStylePlain];
view.sku = sku;
view.image = [images objectAtIndex:indexPath.row];
[self.navigationController pushViewController:view animated:YES];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self tableView:tableView accessoryButtonTappedForRowWithIndexPath:indexPath];
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == ((batch + 1)*25)-1) {
// time to fetch more
self.batch = ++batch;
NSMutableDictionary *batchParameters = [parameters mutableCopy];
if (!batchParameters) batchParameters = [NSMutableDictionary dictionary];
[batchParameters setObject:[NSNumber numberWithInt:batch] forKey:@"batch"];
NSLog(@"batchParameters %@", batchParameters);
[CometAPI get:query parameters:batchParameters completionBlock:^(PLRestful *api, id object, NSInteger status, NSError *error) {
if (error) [self handleError:error];
else {
[self didAddSkus:object];
}
}];
}
}
Other iOS Topics
• Human Interface Guidelines
• Buttons - 44x44
• Gestures
• Controllers - mail, movie, picker
• Other UIControls - switch, slider, page control
• iOS 7
Code Example
• SOE Status
• http://github.com/pauldlynch/SOEStatus
• older version, will update soon
Q&A
Paul Lynch
paul@plsys.co.uk
@pauldlynch

More Related Content

iOS for ERREST - alternative version

  • 1. iOS REST Client Paul Lynch @pauldlynch, paul@plsys.co.uk
  • 2. • Architecture of iOS apps • Comet Architecture • Model Implementation • Controller Implementation • Other iOS Concepts iOS REST Client
  • 3. Architecture of iOS apps • MVC - Model/View/Controller • Objective C • Foundation • UIKit - UIApplication, UIViewController, UIView, UIControl
  • 4. Foundation • NSArray, NSDictionary, NSSet • NSValue • NSPredicate
  • 5. UIKit - UIApplication • UIApplication • status bar • window • orientation • AppDelegate applicationDidFinishLaunchingWithOptions: notifications - UIApplicationWillEnterForegroundNotification, UIApplicationDidEnterBackgroundNotification
  • 7. View Controllers • - (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle • navigationController, tabBarController • rotation, transitions • subclasses - e.g. UITableViewController
  • 8. TableViews • UITableViewController • UITableView • data source • delegate • UITableViewCell
  • 9. Table view data source @protocol UITableViewDataSource<NSObject> - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section; - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section; ... @end @interface NSIndexPath (UITableView) + (NSIndexPath *)indexPathForRow:(NSInteger)row inSection:(NSInteger)section; @property(nonatomic,readonly) NSInteger section; @property(nonatomic,readonly) NSInteger row; @end
  • 10. Table view delegate @protocol UITableViewDelegate<NSObject, UIScrollViewDelegate> ... - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath; ... - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath; ... @end
  • 12. Comet Architecture Marketing db Reviews WO db XML Linux, mySQL Change Report Mobile clients
  • 13. Comet Database Features: skunum, runId; xml/json held as strings Category SKU Review WC7SKU Client
  • 14. REST API • category - parent, children • sku • skudetail - contains full review and XML text • brand - attribute of sku
  • 15. ERREST Routes routeRequestHandler.addRoute(new ERXRoute(Sku.ENTITY_NAME, "/sku", ERXRoute.Method.Options, SkuController.class, "options")); routeRequestHandler.addRoute(new ERXRoute(Sku.ENTITY_NAME, "/sku", ERXRoute.Method.Head, SkuController.class, "head")); routeRequestHandler.addRoute(new ERXRoute(Sku.ENTITY_NAME, "/sku", ERXRoute.Method.All, SkuController.class, "index")); // MS: this only works with numeric ids routeRequestHandler.addRoute(new ERXRoute(Sku.ENTITY_NAME, "/sku/{action:identifier}", ERXRoute.Method.Get, SkuController.class)); routeRequestHandler.addRoute(new ERXRoute(Sku.ENTITY_NAME, "/sku/{sku:Sku}", ERXRoute.Method.Get, SkuController.class, "show")); routeRequestHandler.addRoute(new ERXRoute(Sku.ENTITY_NAME, "/sku/{sku:Sku}/{action:identifier}", ERXRoute.Method.All, SkuController.class)); plus Category, Brand, Skudetail
  • 16. Model Implementation • PLRestful • CometAPI • Sku (etc)
  • 17. PLRestful typedef void (^PLRestfulAPICompletionBlock)(PLRestful *api, id object, NSInteger 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; @property (nonatomic, assign) BOOL useBasicAuthentication; + (NSString *)messageForStatus:(NSInteger)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
  • 18. PLRestful - get - (void)get:(NSString *)requestString parameters:(NSDictionary *)parameters completionBlock: (PLRestfulAPICompletionBlock)completion { NSURL *requestURL = [[NSURL URLWithString:endpoint] urlByAddingPath:requestString parameters:parameters]; NSLog(@"get: '%@'", [requestURL absoluteString]); NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestURL]; [request setHTTPMethod:@"GET"]; [self handleRequest:request completion:(PLRestfulAPICompletionBlock)completion]; }
  • 19. PLRestful - post - (void)post:(NSString *)requestString content:(NSDictionary *)content completionBlock:(PLRestfulAPICompletionBlock)completion { NSURL *requestURL = [[NSURL URLWithString:endpoint] urlByAddingPath:requestString parameters:nil]; NSLog(@"post: '%@'", [requestURL absoluteString]); NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestURL]; [request setHTTPMethod:@"POST"]; NSError *error = nil; request.HTTPBody = [NSJSONSerialization dataWithJSONObject:content options:0 error:&error]; if (error) { NSLog(@"json generation failed: %@", error); [self callCompletionBlockWithObject:nil status:0 error:[NSError errorWithDomain:@"com.plsys.semaphore.CometAPI" code:1003 userInfo:nil]]; return; } [self handleRequest:request completion:completion]; }
  • 20. Controller Implementation • SkuController • subclass of UITableViewController
  • 21. SkuController - data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [skus count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSDictionary *sku = [skus objectAtIndex:indexPath.row]; static NSString *CellIdentifier = @"SkuCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton; } // Configure the cell... cell.textLabel.text = [[sku valueForKey:@"productName"] pl_stringByStrippingHTML]; cell.detailTextLabel.text = [sku valueForKey:@"skuNum"]; id image = [images objectAtIndex:indexPath.row]; if ([image isKindOfClass:[UIImage class]]) { cell.imageView.image = image; } return cell; }
  • 22. SkuController - tv delegate - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath { NSDictionary *sku = [skus objectAtIndex:indexPath.row]; NSString *skuNum = [[sku valueForKey:@"skuNum"] copy]; NSLog(@"tapped: %@", skuNum); SkuDetail *view = [[SkuDetail alloc] initWithStyle:UITableViewStylePlain]; view.sku = sku; view.image = [images objectAtIndex:indexPath.row]; [self.navigationController pushViewController:view animated:YES]; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [self tableView:tableView accessoryButtonTappedForRowWithIndexPath:indexPath]; } - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.row == ((batch + 1)*25)-1) { // time to fetch more self.batch = ++batch; NSMutableDictionary *batchParameters = [parameters mutableCopy]; if (!batchParameters) batchParameters = [NSMutableDictionary dictionary]; [batchParameters setObject:[NSNumber numberWithInt:batch] forKey:@"batch"]; NSLog(@"batchParameters %@", batchParameters); [CometAPI get:query parameters:batchParameters completionBlock:^(PLRestful *api, id object, NSInteger status, NSError *error) { if (error) [self handleError:error]; else { [self didAddSkus:object]; } }]; } }
  • 23. Other iOS Topics • Human Interface Guidelines • Buttons - 44x44 • Gestures • Controllers - mail, movie, picker • Other UIControls - switch, slider, page control • iOS 7
  • 24. Code Example • SOE Status • http://github.com/pauldlynch/SOEStatus • older version, will update soon