Skip to content

Instantly share code, notes, and snippets.

@mikeash
Created February 21, 2011 17:47
Show Gist options
  • Save mikeash/837409 to your computer and use it in GitHub Desktop.
Save mikeash/837409 to your computer and use it in GitHub Desktop.
Block-based URL connection
// NSURLConnection wrapper
// like NSURLConnection, requires a runloop, callbacks happen in runloop that set up load
@interface LDURLLoader : NSObject
{
NSURLConnection *_connection;
NSTimeInterval _timeout;
NSTimer *_timeoutTimer;
NSURLResponse *_response;
long long _responseLengthEstimate;
NSMutableData *_accumulatedData;
void (^_timeoutHandler)(void);
void (^_responseHandler)(NSURLResponse *);
void (^_progressHandler)(long long, long long);
void (^_finishedHandler)(NSData *, NSURLResponse *);
void (^_errorHandler)(NSError *);
}
+ (id)loaderWithURL: (NSURL *)url;
- (id)initWithURL: (NSURL *)url;
- (void)setTimeout: (NSTimeInterval)timeout handler: (void (^)(void))cb;
- (void)setResponseHandler: (void (^)(NSURLResponse *response))cb;
- (void)setProgressHandler: (void (^)(long long soFar, long long total))cb; // total is estimated, -1 means no idea
- (void)setFinishedHandler: (void (^)(NSData *data, NSURLResponse *response))cb;
- (void)setErrorHandler: (void (^)(NSError *error))cb;
// once you've called start, don't fiddle with any of the stuff above, please
- (void)start;
- (void)cancel;
@end
@implementation LDURLLoader
+ (id)loaderWithURL: (NSURL *)url
{
return [[self alloc] initWithURL: url];
}
- (id)initWithURL: (NSURL *)url
{
if((self = [self init]))
{
NSURLRequest *request = [NSURLRequest requestWithURL: url];
_connection = [[NSURLConnection alloc] initWithRequest: request delegate: self startImmediately: NO];
}
return self;
}
- (void)setTimeout: (NSTimeInterval)timeout handler: (void (^)(void))cb
{
_timeout = timeout;
_timeoutHandler = [cb copy];
}
- (void)setResponseHandler: (void (^)(NSURLResponse *response))cb
{
_responseHandler = [cb copy];
}
- (void)setProgressHandler: (void (^)(long long soFar, long long total))cb
{
_progressHandler = [cb copy];
}
- (void)setFinishedHandler: (void (^)(NSData *data, NSURLResponse *response))cb
{
_finishedHandler = [cb copy];
}
- (void)setErrorHandler: (void (^)(NSError *error))cb
{
_errorHandler = [cb copy];
}
- (void)start
{
if(_timeout)
_timeoutTimer = [NSTimer scheduledTimerWithTimeInterval: _timeout target: self selector: @selector( _timeout ) userInfo: nil repeats: NO];
[_connection scheduleInRunLoop: [NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode];
[_connection start];
}
- (void)cancel
{
[_timeoutTimer invalidate];
[_connection cancel];
}
- (void)_timeout
{
[self cancel];
if(_timeoutHandler)
_timeoutHandler();
}
- (void)connection: (NSURLConnection *)connection didReceiveResponse: (NSURLResponse *)response
{
_response = response;
_responseLengthEstimate = [response expectedContentLength];
if(_responseHandler)
_responseHandler(response);
}
- (void)connection: (NSURLConnection *)connection didReceiveData: (NSData *)data
{
if(!_accumulatedData)
_accumulatedData = [[NSMutableData alloc] init];
[_accumulatedData appendData: data];
if(_progressHandler)
_progressHandler([_accumulatedData length], _responseLengthEstimate);
}
- (void)connectionDidFinishLoading: (NSURLConnection *)connection
{
[_timeoutTimer invalidate];
if(_finishedHandler)
_finishedHandler(_accumulatedData, _response);
}
- (void)connection: (NSURLConnection *)connection didFailWithError: (NSError *)error
{
[_timeoutTimer invalidate];
if(_errorHandler)
_errorHandler(error);
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment