-
-
Save codeswimmer/3765358 to your computer and use it in GitHub Desktop.
AsyncURLWrapper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
@class AsyncURLWrapper; | |
@protocol AsyncURLWrapperDelegate <NSObject> | |
@optional | |
- (void) didFinish: (NSData*) data sender: (AsyncURLWrapper*) urlWrapper response: (NSHTTPURLResponse*) response; | |
- (void) didFail: (NSError*) error sender: (AsyncURLWrapper*) urlWrapper; | |
- (void) beforeRetry: (NSError*) error sender: (AsyncURLWrapper*) urlWrapper; | |
- (void) didUpdateProgress: (float) percentCompleted sender: (AsyncURLWrapper*) urlWrapper; | |
@end | |
@interface AsyncURLWrapper : NSObject<NSURLConnectionDelegate> { | |
id<AsyncURLWrapperDelegate> _delegate; | |
NSMutableData * _data; | |
NSNumber* _expectedContentLength; | |
NSURLRequest* _lastRequest; | |
int _tries; | |
int _retries; | |
NSURLConnection* _connection; | |
NSHTTPURLResponse* _lastResponse; | |
} | |
@property (retain) NSTimer* timer; | |
- (void) cancelAndUnload; | |
- (void) cancel; | |
- (id) initWithDelegate: (id<AsyncURLWrapperDelegate>) delegate retries: (int) retries; | |
- (id) initWithRequest: (NSURLRequest*) request delegate: (id<AsyncURLWrapperDelegate>) delegate retries: (int) retries timeout: (NSTimeInterval) timeout; | |
- (id) initWithRequest: (NSURLRequest*) request delegate: (id<AsyncURLWrapperDelegate>) d retries: (int) retries expectedLength: (NSNumber*) expectedContentLength timeout: (NSTimeInterval) timeout; | |
- (void) executeWithRequest: (NSURLRequest*) request timeout: (NSTimeInterval) timeout; | |
+ (NSString*) asUTF8String: (NSData*) data; | |
@end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "AsyncURLWrapper.h" | |
#import <QuartzCore/QuartzCore.h> | |
@implementation AsyncURLWrapper | |
@synthesize timer = _timer; | |
#pragma mark - Utils | |
- (void) connectWithRequest: (NSURLRequest*) request | |
{ | |
_data = [[NSMutableData alloc] init]; | |
_lastRequest = request; | |
_connection=[[NSURLConnection alloc] initWithRequest: request delegate:self startImmediately:YES]; | |
if (_connection) { | |
NSLog(@"connection initialized"); | |
} else { | |
NSLog(@"connection failed"); | |
NSMutableDictionary *errorDetail = [NSMutableDictionary dictionary]; | |
NSString* errorMsg = @"Could not initiate connection"; | |
[errorDetail setValue:errorMsg forKey:NSLocalizedDescriptionKey]; | |
[_timer invalidate]; | |
self.timer = nil; | |
[_delegate didFail:[NSError errorWithDomain:@"asynchronous blob" code:1214 userInfo:errorDetail] sender:self]; //TODO: code and errormsgs should be linked | |
} | |
} | |
-(void) retry: (NSError*) error | |
{ | |
@synchronized(self) { //We synchronize over self for _tries in case you get calls for retry at the same time | |
if (_tries < _retries) { | |
_tries += 1; | |
[_delegate beforeRetry:error sender:self]; | |
[self connectWithRequest:_lastRequest]; | |
} else { | |
[_timer invalidate]; | |
self.timer = nil; | |
[_delegate didFail:error sender:self]; | |
} | |
} | |
} | |
- (void)timeoutAndFail:(NSTimer*)timer | |
{ | |
[self cancel]; | |
if (timer == _timer) { | |
NSMutableDictionary *errorDetail = [NSMutableDictionary dictionary]; | |
NSString* errorMsg = @"Timed out"; | |
[errorDetail setValue:errorMsg forKey:NSLocalizedDescriptionKey]; | |
[_delegate didFail:[NSError errorWithDomain:@"asynchronous blob" code:1215 userInfo:errorDetail] sender:self]; | |
} | |
} | |
#pragma mark - NSURLConnection delegates | |
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error | |
{ | |
[_timer invalidate]; | |
[_delegate didFail:error sender:self]; | |
} | |
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response | |
{ | |
//assuming this is HTTP | |
@synchronized(self) { | |
_lastResponse = (NSHTTPURLResponse *)response; | |
NSInteger statusCode = [_lastResponse statusCode]; | |
if (200 != statusCode) { | |
[self cancel]; | |
NSMutableDictionary *errorDetail = [NSMutableDictionary dictionary]; | |
//TODO: code and errormsgs should be linked | |
NSString* errorMsg = [[NSString alloc] initWithFormat:@"Did not get status code 200. Got: %d", statusCode]; | |
[errorDetail setValue:errorMsg forKey:NSLocalizedDescriptionKey]; | |
if (403 == statusCode || 404 == statusCode) { | |
[self retry: [NSError errorWithDomain:@"asynchronous blob" code:1213 userInfo:errorDetail]]; | |
} else { | |
[_timer invalidate]; | |
self.timer = nil; | |
[_delegate didFail:[NSError errorWithDomain:@"asynchronous blob" code:1212 userInfo:errorDetail] sender:self]; | |
} | |
}else { | |
if ([response expectedContentLength] > 0) { | |
_expectedContentLength = [[NSNumber alloc] initWithLongLong:[response expectedContentLength]]; | |
} | |
NSLog(@"Expected content length: %@", _expectedContentLength); | |
} | |
} | |
} | |
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data | |
{ | |
[_delegate didUpdateProgress: [data length] * 1.0f/ [_expectedContentLength longLongValue] sender:self]; | |
[_data appendData:data]; | |
} | |
- (void)connectionDidFinishLoading:(NSURLConnection *)connection | |
{ | |
[_timer invalidate]; | |
self.timer = nil; | |
@synchronized(self) { | |
[_delegate didFinish:_data sender:self response: _lastResponse]; | |
} | |
} | |
#pragma mark - Impl | |
- (void) cancel | |
{ | |
[_timer invalidate]; | |
self.timer = nil; | |
[_connection cancel]; | |
} | |
- (void) cancelAndUnload | |
{ | |
[self cancel]; | |
_delegate = nil; | |
[_timer invalidate]; | |
self.timer = nil; | |
_data = nil; | |
_expectedContentLength = nil; | |
_lastRequest = nil; | |
_connection = nil; | |
_lastResponse = nil; | |
} | |
- (id) initWithDelegate: (id<AsyncURLWrapperDelegate>) delegate retries: (int) retries | |
{ | |
self = [super init]; | |
_delegate = delegate; | |
_retries = retries; | |
return self; | |
} | |
- (id) initWithRequest: (NSURLRequest*) request delegate: (id<AsyncURLWrapperDelegate>) delegate retries: (int) retries expectedLength: (NSNumber*) expectedContentLength timeout: (NSTimeInterval) timeout | |
{ | |
self = [super init]; | |
_expectedContentLength = expectedContentLength; | |
_delegate = delegate; | |
@synchronized(self) { | |
_retries = retries; | |
} | |
[self executeWithRequest:request timeout:timeout]; | |
return self; | |
} | |
- (id) initWithRequest: (NSURLRequest*) request delegate: (id<AsyncURLWrapperDelegate>) delegate retries: (int) retries timeout: (NSTimeInterval) timeout | |
{ | |
return [self initWithRequest:request delegate:delegate retries: retries expectedLength:nil timeout:timeout]; | |
} | |
- (void) executeWithRequest: (NSURLRequest*) request timeout: (NSTimeInterval) timeout | |
{ | |
@synchronized(self) { | |
_tries = 0; | |
} | |
[_timer invalidate]; | |
self.timer = nil; | |
_timer = [NSTimer timerWithTimeInterval:timeout target:self selector:@selector(timeoutAndFail:) userInfo:nil repeats:NO]; | |
[self connectWithRequest:request]; | |
} | |
+ (NSString*) asUTF8String: (NSData*) data | |
{ | |
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment