Blocks Rock – A Cocoa Asynchronous NSURLConnection block example
So I heard that blocks were one of the new features of 4.1 and I decided to give it a try. And it’s awesome! Within half an hour I’d solved a problem that I’d had to make much more complicated implementations to solve previously, and I’m so excited I decided I’d share the code.
Problem: NSURLConnection asynchronous connections are ugly. If you want to have one controller make multiple different calls you have to make unique delegates for each call or have some convoluted way for the connection manager to tell one delegate from another. It’s a real mess.
Solution: BLOCKS!
Step 1: Create NSURLConnection block extension that allows for calling async methods from class API like you would sync method.
// // NSURLConnection-block.h // // Created by Kevin Lohman on 9/12/10. // Copyright 2010 Logic High Software. All rights reserved. // Free to use in your code commercial or otherwise, as long as you leave this comment block in // http://blog.logichigh.com/2010/09/12/cocoa-blocks/ #import@interface NSURLConnection (block) #pragma mark Class API Extensions + (void)asyncRequest:(NSURLRequest *)request success:(void(^)(NSData *,NSURLResponse *))successBlock_ failure:(void(^)(NSData *,NSError *))failureBlock_; @end
and
#import "NSURLConnection-block.h"
@implementation NSURLConnection (block)
#pragma mark API
+ (void)asyncRequest:(NSURLRequest *)request success:(void(^)(NSData *,NSURLResponse *))successBlock_ failure:(void(^)(NSData *,NSError *))failureBlock_
{
[NSThread detachNewThreadSelector:@selector(backgroundSync:) toTarget:[NSURLConnection class]
withObject:[NSDictionary dictionaryWithObjectsAndKeys:
request,@"request",
successBlock_,@"success",
failureBlock_,@"failure",
nil]];
}
#pragma mark Private
+ (void)backgroundSync:(NSDictionary *)dictionary
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
void(^success)(NSData *,NSURLResponse *) = [dictionary objectForKey:@"success"];
void(^failure)(NSData *,NSError *) = [dictionary objectForKey:@"failure"];
NSURLRequest *request = [dictionary objectForKey:@"request"];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if(error)
{
failure(data,error);
}
else
{
success(data,response);
}
[pool release];
}
@end
Now just import your new class and make your async call! AWESOME!
[NSURLConnection asyncRequest:request
success:^(NSData *data, NSURLResponse *response) {
NSLog(@"Success!");
}
failure:^(NSData *data, NSError *error) {
NSLog(@"Error! %@",[error localizedDescription]);
}];