Skip to content

Instantly share code, notes, and snippets.

@spr
Last active March 22, 2017 10:57
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save spr/4751706 to your computer and use it in GitHub Desktop.
Save spr/4751706 to your computer and use it in GitHub Desktop.
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
Copy link

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
Copy link

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