working with afnetworking

Post on 27-Jan-2015

115 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

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

Working With

AFNetworking

@waynehartman

Before AFNetworking

• NSURLConnection (meh)

• NSData (BARF!)

• CFNetwork (medic!)

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"}

NSData• One line of code! !

dataWithContentsOfURL: !

NEVER USE THIS API!

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()

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.”

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];

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]; };

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]; } };

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; }

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.

Demo: Using Queues

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.

AFURLResponseSerializerAFJSONResponseSerializer

AFPropertyListResponseSerializer

AFImageResponseSerializer

AFCompoundResponseSerializer

AFXMLParserResponseSerializer

!

AFXMLDocumentResponseSerializer

Custom Serializer

• Subclass AFHTTPResponseSerializer

• Override

• responseObjectForResponse:data:error:

• acceptableContentTypes

Custom Serializer

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

Anyone know the Content-Type for 1337 encoded data?

@99l1c@710n/l337

D3m0: Cu570m R3590n53 53r1@l1z@710n

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

classes:

• UIImageView

• UIButton

• UIWebView

• UIProgressView

• UIRefreshControl

Demo: UIKit Extensions

Design Patterns for Network & Data

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

Justin Spahr-Summers CocoaConf Austin 2014

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.

Are your View Controllers like this?

Case Study:

Geekdom for iOS

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

Questions?

@waynehartman

top related