Skip to content

Instantly share code, notes, and snippets.

@pizthewiz
Forked from mikeash/gist:837409
Created August 2, 2011 19:47
Show Gist options
  • Save pizthewiz/1121036 to your computer and use it in GitHub Desktop.
Save pizthewiz/1121036 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)loaderWithRequest:(NSURLRequest*)request;
+ (id)loaderWithURL:(NSURL*)url;
- (id)initWithRequest:(NSURLRequest*)request;
- (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] initWithRequest:[NSURLRequest requestWithURL:url]];
}
+ (id)loaderWithRequest:(NSURLRequest*)request {
return [[self alloc] initWithRequest:request];
}
- (id)initWithRequest:(NSURLRequest*)request {
self = [super init];
if (self) {
_connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
}
return self;
}
- (id)initWithURL:(NSURL*)url {
NSURLRequest* request = [[NSURLRequest alloc] initWithURL:url];
self = [self initWithRequest:request];
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 mainRunLoop] forMode:NSRunLoopCommonModes];
[_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
@pizthewiz
Copy link
Author

now retain/release savvy (previously, i think it was targeting ARC) and offer class/instance initializers with an NSURLRequest, not just an NSURL.

@pizthewiz
Copy link
Author

retain and release is for suckers, ARC or nothing.

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