Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
An Example NSURLConnection delegate
//
// ExampleDelegate.h
// Example
//
// Created by Scott Robertson on 2/10/13.
// Copyright (c) 2013 Scott Robertson. All rights reserved.
//
#import <Foundation/Foundation.h>
typedef void (^ExampleDelegateSuccess) (NSData *theData);
typedef void (^ExampleDelegateFailure) (NSError *theError);
@interface ExampleDelegate : NSObject <NSURLConnectionDelegate,NSURLConnectionDataDelegate>
@property (nonatomic,readwrite) NSTimeInterval timeout;
@property (nonatomic,readwrite) NSURLRequestCachePolicy cachePolicy;
- (void)fetchURL:(NSURL *)url withCompletion:(ExampleDelegateSuccess)completion failure:(ExampleDelegateFailure)failure;
- (void)cancelAllCalls;
@end
//
// ExampleDelegate.m
// Example
//
// Created by Scott Robertson on 2/10/13.
// Copyright (c) 2013 Scott Robertson. All rights reserved.
//
#import "ExampleDelegate.h"
@interface ExampleURLConnection : NSURLConnection
@property (nonatomic,readwrite,strong) ExampleDelegateSuccess completion;
@property (nonatomic,readwrite,strong) ExampleDelegateFailure failure;
@property (nonatomic,readwrite,strong) NSMutableData *data;
@property (nonatomic,readwrite,strong) NSURLResponse *response;
@end
@implementation ExampleURLConnection
@end
@interface ExampleDelegate ()
@property (nonatomic,readwrite,strong) NSMutableArray *connections;
@property (nonatomic,readwrite,strong) NSOperationQueue *networkQueue;
@end
@implementation ExampleDelegate
- (id)init {
self = [super init];
if (self) {
_networkQueue = [[NSOperationQueue alloc] init];
// We just have 1 thread for this work, that way canceling is easy
_networkQueue.maxConcurrentOperationCount = 1;
_connections = [NSMutableArray arrayWithCapacity:10];
_timeout = 5.0;
_cachePolicy = NSURLRequestUseProtocolCachePolicy;
}
return self;
}
- (void)fetchURL:(NSURL *)url withCompletion:(ExampleDelegateSuccess)completion failure:(ExampleDelegateFailure)failure {
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:self.cachePolicy timeoutInterval:self.timeout];
ExampleURLConnection *connection = [[ExampleURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
if (!connection) {
failure([NSError errorWithDomain:@"ExampleDelegate" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Could not initialize NSURLConnection"}]);
return;
}
[connection setDelegateQueue:self.networkQueue];
connection.data = [NSMutableData dataWithCapacity:1024];
connection.completion = completion;
connection.failure = failure;
[connection start];
[self.connections addObject:connection];
}
// This prevents new callbacks from being queued, cancels any queued callbacks
// from being run, and then adds an operation on the queue to cancel all
// connections and clean up the array we use.
- (void)cancelAllCalls {
[self.networkQueue setSuspended:YES];
[self.networkQueue cancelAllOperations];
[self.networkQueue addOperationWithBlock:^{
for (ExampleURLConnection *connection in self.connections) {
[connection cancel];
connection.failure([NSError errorWithDomain:@"ExampleDelegate" code:-2 userInfo:@{NSLocalizedDescriptionKey: @"Call canceled by user"}]);
}
[self.connections removeAllObjects];
}];
[self.networkQueue setSuspended:NO];
}
#pragma mark - NSURLConnectionDelegate
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
ExampleURLConnection *exConnection = (ExampleURLConnection *)connection;
exConnection.failure(error);
[self.connections removeObject:exConnection];
}
#pragma mark - NSURLConnectionDataDelegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
ExampleURLConnection *exConnection = (ExampleURLConnection *)connection;
exConnection.response = response;
exConnection.data.length = 0;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
ExampleURLConnection *exConnection = (ExampleURLConnection *)connection;
[exConnection.data appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[self.connections removeObject:connection];
ExampleURLConnection *exConnection = (ExampleURLConnection *)connection;
if ([exConnection.response isKindOfClass:[NSHTTPURLResponse class]]) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)exConnection.response;
if (httpResponse.statusCode >= 400) { // Client/Server Error
exConnection.failure([NSError errorWithDomain:@"ExampleDelegate" code:httpResponse.statusCode userInfo:@{NSLocalizedDescriptionKey: [NSHTTPURLResponse localizedStringForStatusCode:httpResponse.statusCode]}]);
return;
}
}
exConnection.completion(exConnection.data);
}
@end

dhoerl commented May 3, 2013

Nice code, but you offer no license to use. If its BSD/MIT please update, otherwise its just for the curious. In any case a nice bit of code! You might add that setDelegateQueue does not function properly on iOS5 but does as of iOS6 (google setDelegateQueue).

MDWULFF commented May 3, 2013

I've been looking for something like this for a while now. A lot of this syntax looks a lot more advanced than most of what I'm used to though.

I just registered - is it okay to ask questions here?

If so, how would I actually call fetchURL, say from a UIViewController? I did #include ExampleDelegate.h, then

NSURL *url = [NSURL URLWithString:@"http://www.mysite.com/download/database.sqlite"];
NSError *error;
NSData *fileData;
ExampleDelegate *download = [[ExampleDelegate alloc] init];
[download fetchURL:url withCompletion:fileData failure:&error];

I get incompatible pointer errors on the last line for fileData and error. I didn't really expect this to work, but I have no idea what I need to do differently. I have a question for this posted on Stack Overflow that has more info here: http://stackoverflow.com/questions/16150196/updating-sqlite-database-without-xml (see Update2 for the part referring to this example).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment