working with afnetworking

33
Working With AFNetworking @waynehartman

Upload: waynehartman

Post on 27-Jan-2015

115 views

Category:

Technology


2 download

DESCRIPTION

It's difficult to find any app that doesn't connect to the network to get data. If you have used NSURLConnection you know that fetching data is easy, but can be fraught with a messy implementation. AFNetworking is delightful networking library for iOS and Mac that can simplify the process of getting JSON data, XML, or even images.

TRANSCRIPT

Page 1: Working with AFNetworking

Working With

AFNetworking

@waynehartman

Page 2: Working with AFNetworking

Before AFNetworking

• NSURLConnection (meh)

• NSData (BARF!)

• CFNetwork (medic!)

Page 3: Working with AFNetworking

NSURLConnection - (IBAction)didSelectRefreshButton:(id)sender { NSURL *url = [NSURL URLWithString:@"http://ip.jsontest.com/"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; ! self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]; } !#pragma mark - NSURLConnection !- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response { _data = nil; ! switch (response.statusCode) { case 200: { self.data = [NSMutableData dataWithCapacity:(NSUInteger)response.expectedContentLength]; } break; default: { [connection cancel]; ! NSError *error = [NSError errorWithDomain:(NSString *)kCFErrorDomainCFNetwork code:response.statusCode userInfo:@{(NSString *)kCFErrorDescriptionKey : (NSString *)kCFURLErrorFailingURLErrorKey}]; [self connection:connection didFailWithError:error]; } break; } } !- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [self.data appendData:data]; } !- (void)connectionDidFinishLoading:(NSURLConnection *)connection { NSError *error = nil; NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:self.data options:0 error:&error]; if (!jsonData) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"The data was corrupt. Sorry" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; } else { NSString *ip = jsonData[@"ip"]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Success!" message:[NSString stringWithFormat:@"Your IP is: %@", ip] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; } ! self.connection = nil; } !- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"There was an error getting the data. Please try again later." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; self.connection = nil; }

• All this code, just to download and display this:

{"ip": "72.191.49.142"}

Page 4: Working with AFNetworking

NSData• One line of code! !

dataWithContentsOfURL: !

NEVER USE THIS API!

Page 5: Working with AFNetworking

CFNetwork NSURL *url = [NSURL URLWithString:DOWNLOAD_URL]; ! CFHTTPMessageRef request = CFHTTPMessageCreateRequest(NULL, CFSTR("GET"), (__bridge CFURLRef)url, kCFHTTPVersion1_1); ! CFReadStreamRef requestStream = CFReadStreamCreateForHTTPRequest(NULL, request); CFReadStreamOpen(requestStream); NSMutableData *responseBytes = [NSMutableData data]; CFIndex numBytesRead = 0 ; NSUInteger totalBytesRead = 0; ! do { UInt8 buf[1024]; numBytesRead = CFReadStreamRead(requestStream, buf, sizeof(buf)); if(numBytesRead > 0) { [responseBytes appendBytes:buf length:numBytesRead]; totalBytesRead += numBytesRead; } } while(numBytesRead > 0); if (totalBytesRead > 0) { CFHTTPMessageRef response = (CFHTTPMessageRef)CFReadStreamCopyProperty(requestStream, kCFStreamPropertyHTTPResponseHeader); CFHTTPMessageSetBody(response, (__bridge CFDataRef)responseBytes); CFReadStreamClose(requestStream); CFDataRef responseBodyData = CFHTTPMessageCopyBody(response); NSError *error = nil; NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:(__bridge NSData *)responseBodyData options:0 error:&error]; CFRelease(responseBodyData); CFRelease(response); if (!jsonData) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"The data was corrupt. Sorry" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; } else { NSString *ip = jsonData[@"ip"]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Success!" message:[NSString stringWithFormat:@"Your IP is: %@", ip] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; } } else { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"There was an error getting the data. Please try again later." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; } ! CFRelease(requestStream); CFRelease(request);

• All this code, just to download and display this:

{"ip": "72.191.49.142"}

• Plus we have to write gross C with nasty CFRelease()

Page 6: Working with AFNetworking

AFNetworking

“AFNetworking is a delightful networking library for iOS and Mac OS X. It's built on top of the Foundation URL Loading System, extending the powerful high-level networking abstractions built into Cocoa. It has a modular architecture with well-designed, feature-rich APIs that are a joy to use.”

Page 7: Working with AFNetworking

AFNetworking

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:DOWNLOAD_URL]]; !AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; [operation setResponseSerializer:[AFJSONResponseSerializer serializer]]; [operation setCompletionBlockWithSuccess:successHandler failure:failureHandler]; ![operation start];

Page 8: Working with AFNetworking

AFNetworking

void(^failureHandler)(AFHTTPRequestOperation *, NSError *) = ^(AFHTTPRequestOperation *operation, NSError *error) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"There was an error getting the data. Please try again later." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; };

Page 9: Working with AFNetworking

AFNetworking

void(^successHandler)(AFHTTPRequestOperation *, id) = ^(AFHTTPRequestOperation *operation, id responseObject) { if (!responseObject) { failureHandler(operation, [NSError errorWithDomain:AFNetworkingErrorDomain code:404 userInfo:nil]); } else { NSString *ip = responseObject[@"ip"]; ! UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Success!" message:[NSString stringWithFormat:@"Your IP is: %@", ip] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; } };

Page 10: Working with AFNetworking

void(^failureHandler)(AFHTTPRequestOperation *, NSError *) = ^(AFHTTPRequestOperation *operation, NSError *error) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"There was an error getting the data. Please try again later." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; }; void(^successHandler)(AFHTTPRequestOperation *, id) = ^(AFHTTPRequestOperation *operation, id responseObject) { if (!responseObject) { failureHandler(operation, [NSError errorWithDomain:AFNetworkingErrorDomain code:404 userInfo:nil]); } else { NSString *ip = responseObject[@"ip"]; ! UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Success!" message:[NSString stringWithFormat:@"Your IP is: %@", ip] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; } }; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:DOWNLOAD_URL]]; AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; [operation setResponseSerializer:[AFJSONResponseSerializer serializer]]; [operation setCompletionBlockWithSuccess:successHandler failure:failureHandler]; ![operation start];

- (IBAction)didSelectRefreshButton:(id)sender { NSURL *url = [NSURL URLWithString:@"http://ip.jsontest.com/"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; ! self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]; } !#pragma mark - NSURLConnection !- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response { _data = nil; ! switch (response.statusCode) { case 200: { self.data = [NSMutableData dataWithCapacity:(NSUInteger)response.expectedContentLength]; } break; default: { [connection cancel]; ! NSError *error = [NSError errorWithDomain:(NSString *)kCFErrorDomainCFNetwork code:response.statusCode userInfo:@{(NSString *)kCFErrorDescriptionKey : (NSString *)kCFURLErrorFailingURLErrorKey}]; [self connection:connection didFailWithError:error]; } break; } } !- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [self.data appendData:data]; } !- (void)connectionDidFinishLoading:(NSURLConnection *)connection { NSError *error = nil; NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:self.data options:0 error:&error]; if (!jsonData) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"The data was corrupt. Sorry" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; } else { NSString *ip = jsonData[@"ip"]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Success!" message:[NSString stringWithFormat:@"Your IP is: %@", ip] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; } ! self.connection = nil; } !- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"There was an error getting the data. Please try again later." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; self.connection = nil; }

Page 11: Working with AFNetworking
Page 12: Working with AFNetworking

Key Concepts

• AF*Operation are subclasses of NSOperation

• Networking operations can be started individually or placed in an NSOperationQueue

• Custom serialization classes can be created for transforming and validating data.

Page 13: Working with AFNetworking

Demo: Using Queues

Page 14: Working with AFNetworking

AFURLResponseSerializer

• If you don’t specify a request/response serializer, it will give back NSData.

• Serializers can be created to handle data transformation and validation.

Page 15: Working with AFNetworking

AFURLResponseSerializerAFJSONResponseSerializer

AFPropertyListResponseSerializer

AFImageResponseSerializer

AFCompoundResponseSerializer

AFXMLParserResponseSerializer

!

AFXMLDocumentResponseSerializer

Page 16: Working with AFNetworking

Custom Serializer

• Subclass AFHTTPResponseSerializer

• Override

• responseObjectForResponse:data:error:

• acceptableContentTypes

Page 17: Working with AFNetworking

Custom Serializer

• We’re going to create a serializer for decoding 1337593@k

Page 18: Working with AFNetworking

Anyone know the Content-Type for 1337 encoded data?

Page 19: Working with AFNetworking

@99l1c@710n/l337

Page 20: Working with AFNetworking

D3m0: Cu570m R3590n53 53r1@l1z@710n

Page 21: Working with AFNetworking

AFNetworking + UIKit• AFNetworking adds a number of extensions to common UIKit

classes:

• UIImageView

• UIButton

• UIWebView

• UIProgressView

• UIRefreshControl

Page 22: Working with AFNetworking

Demo: UIKit Extensions

Page 23: Working with AFNetworking

Design Patterns for Network & Data

Page 24: Working with AFNetworking

“At its heart, programming is all about abstraction.”

Justin Spahr-Summers CocoaConf Austin 2014

Page 25: Working with AFNetworking

Classes should have as few purposes as possible (say, one) and do it very well. !

Classes should know as little as possible about other classes.

Page 26: Working with AFNetworking

Are your View Controllers like this?

Page 27: Working with AFNetworking

Case Study:

Geekdom for iOS

Page 28: Working with AFNetworking
Page 29: Working with AFNetworking

Monster View Controller• UITableView Datasource • Configure Cells • UITableView Delegate • Showing Member Details • NSFetchedResultsControllerDelegate • Fetch All Member data • Fetch Checked-In Members • Fetch Profile Images • Search Members By Name • Search Members By Skills • Data Persistance • Check-In logic • Checked-In vs All Members

Page 30: Working with AFNetworking
Page 31: Working with AFNetworking
Page 32: Working with AFNetworking

Questions?

Page 33: Working with AFNetworking

@waynehartman