From ccdc5f2d9b98db81c3063e9dfa85de8ea0b51e4d Mon Sep 17 00:00:00 2001 From: Mattt Thompson Date: Wed, 5 Oct 2011 12:36:45 -0500 Subject: [PATCH] Approaching a reasonable design for restructuring AFHTTPRequestOperation and subclasses --- AFNetworking/AFHTTPClient.h | 7 ++-- AFNetworking/AFHTTPClient.m | 14 +++---- AFNetworking/AFHTTPRequestOperation.h | 6 +++ AFNetworking/AFHTTPRequestOperation.m | 7 ++-- AFNetworking/AFImageRequestOperation.h | 7 +++- AFNetworking/AFImageRequestOperation.m | 51 +++++++++++++++++++------ AFNetworking/AFJSONRequestOperation.h | 4 +- AFNetworking/AFJSONRequestOperation.m | 19 ++++++--- AFNetworking/AFURLConnectionOperation.h | 2 +- AFNetworking/AFURLConnectionOperation.m | 13 ++++--- 10 files changed, 89 insertions(+), 41 deletions(-) diff --git a/AFNetworking/AFHTTPClient.h b/AFNetworking/AFHTTPClient.h index 7ac8177..c095d28 100644 --- a/AFNetworking/AFHTTPClient.h +++ b/AFNetworking/AFHTTPClient.h @@ -183,9 +183,9 @@ @param success A block object to be executed when the request operation finishes successfully, with a status code in the 2xx range, and with an acceptable content type (e.g. `application/json`). This block has no return value and takes a single argument, which is an object created from the response data of request. @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data as JSON. This block has no return value and takes a single argument, which is the `NSError` object describing the network or parsing error that occurred. */ -- (void)enqueueHTTPOperationWithRequest:(NSURLRequest *)request - success:(void (^)(id object))success - failure:(void (^)(NSHTTPURLResponse *response, NSError *error))failure; +- (void)enqueueHTTPRequestOperationWithRequest:(NSURLRequest *)request + success:(void (^)(id object))success + failure:(void (^)(NSHTTPURLResponse *response, NSError *error))failure; ///--------------------------------- /// @name Cancelling HTTP Operations @@ -322,3 +322,4 @@ */ - (void)appendString:(NSString *)string; @end + diff --git a/AFNetworking/AFHTTPClient.m b/AFNetworking/AFHTTPClient.m index b2b5041..05f989a 100644 --- a/AFNetworking/AFHTTPClient.m +++ b/AFNetworking/AFHTTPClient.m @@ -224,9 +224,9 @@ static NSString * AFURLEncodedStringFromStringWithEncoding(NSString *string, NSS return request; } -- (void)enqueueHTTPOperationWithRequest:(NSURLRequest *)urlRequest - success:(void (^)(id object))success - failure:(void (^)(NSHTTPURLResponse *response, NSError *error))failure +- (void)enqueueHTTPRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(id object))success + failure:(void (^)(NSHTTPURLResponse *response, NSError *error))failure { AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:urlRequest success:^(__unused NSURLRequest *request, __unused NSHTTPURLResponse *response, id JSON) { if (success) { @@ -257,7 +257,7 @@ static NSString * AFURLEncodedStringFromStringWithEncoding(NSString *string, NSS failure:(void (^)(NSHTTPURLResponse *response, NSError *error))failure { NSURLRequest *request = [self requestWithMethod:@"GET" path:path parameters:parameters]; - [self enqueueHTTPOperationWithRequest:request success:success failure:failure]; + [self enqueueHTTPRequestOperationWithRequest:request success:success failure:failure]; } - (void)postPath:(NSString *)path @@ -266,7 +266,7 @@ static NSString * AFURLEncodedStringFromStringWithEncoding(NSString *string, NSS failure:(void (^)(NSHTTPURLResponse *response, NSError *error))failure { NSURLRequest *request = [self requestWithMethod:@"POST" path:path parameters:parameters]; - [self enqueueHTTPOperationWithRequest:request success:success failure:failure]; + [self enqueueHTTPRequestOperationWithRequest:request success:success failure:failure]; } - (void)putPath:(NSString *)path @@ -275,7 +275,7 @@ static NSString * AFURLEncodedStringFromStringWithEncoding(NSString *string, NSS failure:(void (^)(NSHTTPURLResponse *response, NSError *error))failure { NSURLRequest *request = [self requestWithMethod:@"PUT" path:path parameters:parameters]; - [self enqueueHTTPOperationWithRequest:request success:success failure:failure]; + [self enqueueHTTPRequestOperationWithRequest:request success:success failure:failure]; } - (void)deletePath:(NSString *)path @@ -284,7 +284,7 @@ static NSString * AFURLEncodedStringFromStringWithEncoding(NSString *string, NSS failure:(void (^)(NSHTTPURLResponse *response, NSError *error))failure { NSURLRequest *request = [self requestWithMethod:@"DELETE" path:path parameters:parameters]; - [self enqueueHTTPOperationWithRequest:request success:success failure:failure]; + [self enqueueHTTPRequestOperationWithRequest:request success:success failure:failure]; } @end diff --git a/AFNetworking/AFHTTPRequestOperation.h b/AFNetworking/AFHTTPRequestOperation.h index 283753b..714c1a4 100644 --- a/AFNetworking/AFHTTPRequestOperation.h +++ b/AFNetworking/AFHTTPRequestOperation.h @@ -23,6 +23,11 @@ #import #import "AFURLConnectionOperation.h" +@protocol AFHTTPClientRequestOperation ++ (BOOL)canInitWithRequest:(NSURLRequest *)request; ++ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request; +@end + /** `AFHTTPRequestOperation` is an `NSOperation` subclass that implements the `NSURLConnection` delegate methods, and provides a simple block-based interface to asynchronously get the result and context of that operation finishes. @@ -58,6 +63,7 @@ @private NSIndexSet *_acceptableStatusCodes; NSSet *_acceptableContentTypes; + NSError *_HTTPError; } @property (readonly, nonatomic, retain) NSHTTPURLResponse *response; diff --git a/AFNetworking/AFHTTPRequestOperation.m b/AFNetworking/AFHTTPRequestOperation.m index 422cd1f..5e8bd60 100644 --- a/AFNetworking/AFHTTPRequestOperation.m +++ b/AFNetworking/AFHTTPRequestOperation.m @@ -27,10 +27,9 @@ @end @implementation AFHTTPRequestOperation -@dynamic error; -@dynamic response; @synthesize acceptableStatusCodes = _acceptableStatusCodes; @synthesize acceptableContentTypes = _acceptableContentTypes; +@synthesize error = _HTTPError; + (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)urlRequest success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSData *data))success @@ -51,7 +50,7 @@ } else { if (success) { dispatch_async(dispatch_get_main_queue(), ^(void) { - success(operation.request, operation.response, operation.responseBody); + success(operation.request, operation.response, operation.responseData); }); } } @@ -81,7 +80,7 @@ } - (NSError *)error { - if (self.response && ![super error]) { + if (self.response) { if (![self hasAcceptableStatusCode]) { NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; [userInfo setValue:[NSString stringWithFormat:NSLocalizedString(@"Expected status code %@, got %d", nil), self.acceptableStatusCodes, [self.response statusCode]] forKey:NSLocalizedDescriptionKey]; diff --git a/AFNetworking/AFImageRequestOperation.h b/AFNetworking/AFImageRequestOperation.h index 8639bfc..b7ee9bb 100644 --- a/AFNetworking/AFImageRequestOperation.h +++ b/AFNetworking/AFImageRequestOperation.h @@ -30,7 +30,12 @@ @see NSOperation @see AFHTTPRequestOperation */ -@interface AFImageRequestOperation : AFHTTPRequestOperation +@interface AFImageRequestOperation : AFHTTPRequestOperation { +@private + UIImage *_responseImage; +} + +@property (readonly, nonatomic, retain) UIImage *responseImage; /** Creates and returns an `AFImageRequestOperation` object and sets the specified success callback. diff --git a/AFNetworking/AFImageRequestOperation.m b/AFNetworking/AFImageRequestOperation.m index 70bfd59..a1062b4 100644 --- a/AFNetworking/AFImageRequestOperation.m +++ b/AFNetworking/AFImageRequestOperation.m @@ -32,7 +32,26 @@ static dispatch_queue_t image_request_operation_processing_queue() { return af_image_request_operation_processing_queue; } +@interface AFImageRequestOperation () +@property (readwrite, nonatomic, retain) UIImage *responseImage; + ++ (UIImage *)imageWithData:(NSData *)data error:(NSError **)error ; +@end + @implementation AFImageRequestOperation +@synthesize responseImage = _responseImage; + ++ (UIImage *)imageWithData:(NSData *)data error:(NSError **)__unused error { + UIImage *image = nil; + if ([[UIScreen mainScreen] scale] == 2.0) { + CGImageRef imageRef = [[UIImage imageWithData:data] CGImage]; + image = [UIImage imageWithCGImage:imageRef scale:2.0 orientation:UIImageOrientationUp]; + } else { + image = [UIImage imageWithData:data]; + } + + return image; +} + (AFImageRequestOperation *)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest success:(void (^)(UIImage *image))success @@ -64,24 +83,19 @@ static dispatch_queue_t image_request_operation_processing_queue() { failure(operation.request, operation.response, operation.error); }); } - } else { - UIImage *image = nil; - if ([[UIScreen mainScreen] scale] == 2.0) { - CGImageRef imageRef = [[UIImage imageWithData:operation.responseBody] CGImage]; - image = [UIImage imageWithCGImage:imageRef scale:2.0 orientation:UIImageOrientationUp]; - } else { - image = [UIImage imageWithData:operation.responseBody]; - } + } else { + UIImage *image = [[self class] imageWithData:operation.responseData error:nil]; if (imageProcessingBlock) { image = imageProcessingBlock(image); } - dispatch_async(dispatch_get_main_queue(), ^(void) { - if (success) { + if (success) { + dispatch_async(dispatch_get_main_queue(), ^(void) { + success(operation.request, operation.response, image); - } - }); + }); + } if ([operation.request cachePolicy] != NSURLCacheStorageNotAllowed) { [[AFImageCache sharedImageCache] cacheImage:image forURL:[operation.request URL] cacheName:cacheNameOrNil]; @@ -104,4 +118,17 @@ static dispatch_queue_t image_request_operation_processing_queue() { return self; } +- (void)dealloc { + [_responseImage release]; + [super dealloc]; +} + +- (UIImage *)responseImage { + if (!_responseImage && [self isFinished]) { + self.responseImage = [[self class] imageWithData:self.responseData error:nil]; + } + + return _responseImage; +} + @end diff --git a/AFNetworking/AFJSONRequestOperation.h b/AFNetworking/AFJSONRequestOperation.h index 96b890f..08d1aee 100644 --- a/AFNetworking/AFJSONRequestOperation.h +++ b/AFNetworking/AFJSONRequestOperation.h @@ -31,12 +31,12 @@ */ @interface AFJSONRequestOperation : AFHTTPRequestOperation { @private - id _responseJSON; + id _responseJSON; + NSError *_JSONError; } @property (readonly, nonatomic, retain) id responseJSON; - ///--------------------------------------- /// @name Creating JSON Request Operations ///--------------------------------------- diff --git a/AFNetworking/AFJSONRequestOperation.m b/AFNetworking/AFJSONRequestOperation.m index 5ba411b..a820212 100644 --- a/AFNetworking/AFJSONRequestOperation.m +++ b/AFNetworking/AFJSONRequestOperation.m @@ -36,12 +36,14 @@ static dispatch_queue_t json_request_operation_processing_queue() { @interface AFJSONRequestOperation () @property (readwrite, nonatomic, retain) id responseJSON; +@property (readwrite, nonatomic, retain) NSError *error; + (id)JSONObjectWithData:(NSData *)data error:(NSError **)error; @end @implementation AFJSONRequestOperation @synthesize responseJSON = _responseJSON; +@synthesize error = _JSONError; + (id)JSONObjectWithData:(NSData *)data error:(NSError **)error { id JSON = nil; @@ -55,7 +57,7 @@ static dispatch_queue_t json_request_operation_processing_queue() { #else JSON = [[JSONDecoder decoder] objectWithData:data error:error]; #endif - + return JSON; } @@ -65,6 +67,10 @@ static dispatch_queue_t json_request_operation_processing_queue() { { AFJSONRequestOperation *operation = [[[AFJSONRequestOperation alloc] initWithRequest:urlRequest] autorelease]; operation.completionBlock = ^ { + if ([operation isCancelled]) { + return; + } + if (operation.error) { if (failure) { dispatch_async(dispatch_get_main_queue(), ^(void) { @@ -74,10 +80,11 @@ static dispatch_queue_t json_request_operation_processing_queue() { } else { dispatch_async(json_request_operation_processing_queue(), ^(void) { NSError *error = nil; - id JSON = [self JSONObjectWithData:operation.responseBody error:&error]; + id JSON = [self JSONObjectWithData:operation.responseData error:&error]; + operation.error = error; dispatch_async(dispatch_get_main_queue(), ^(void) { - if (error) { + if (operation.error) { if (failure) { failure(operation.request, operation.response, error); } @@ -111,8 +118,10 @@ static dispatch_queue_t json_request_operation_processing_queue() { } - (id)responseJSON { - if (!_responseJSON && self.response && self.responseBody) { - self.responseJSON = [[self class] JSONObjectWithData:self.responseBody error:nil]; + if (!_responseJSON && [self isFinished]) { + NSError *error = nil; + self.responseJSON = [[self class] JSONObjectWithData:self.responseData error:nil]; + self.error = error; } return _responseJSON; diff --git a/AFNetworking/AFURLConnectionOperation.h b/AFNetworking/AFURLConnectionOperation.h index 56847d1..9c7ba9a 100644 --- a/AFNetworking/AFURLConnectionOperation.h +++ b/AFNetworking/AFURLConnectionOperation.h @@ -61,7 +61,7 @@ extern NSString * const AFNetworkingOperationDidFinishNotification; @property (readonly, nonatomic, retain) NSURLResponse *response; @property (readonly, nonatomic, retain) NSError *error; -@property (readonly, nonatomic, retain) NSData *responseBody; +@property (readonly, nonatomic, retain) NSData *responseData; @property (readonly, nonatomic, copy) NSString *responseString; @property (nonatomic, retain) NSInputStream *inputStream; diff --git a/AFNetworking/AFURLConnectionOperation.m b/AFNetworking/AFURLConnectionOperation.m index 8500a33..8540ad1 100644 --- a/AFNetworking/AFURLConnectionOperation.m +++ b/AFNetworking/AFURLConnectionOperation.m @@ -58,7 +58,7 @@ static inline NSString * AFKeyPathFromOperationState(AFOperationState state) { @property (readwrite, nonatomic, retain) NSURLRequest *request; @property (readwrite, nonatomic, retain) NSURLResponse *response; @property (readwrite, nonatomic, retain) NSError *error; -@property (readwrite, nonatomic, retain) NSData *responseBody; +@property (readwrite, nonatomic, retain) NSData *responseData; @property (readwrite, nonatomic, copy) NSString *responseString; @property (readwrite, nonatomic, assign) NSInteger totalBytesRead; @property (readwrite, nonatomic, retain) NSMutableData *dataAccumulator; @@ -78,7 +78,7 @@ static inline NSString * AFKeyPathFromOperationState(AFOperationState state) { @synthesize request = _request; @synthesize response = _response; @synthesize error = _error; -@synthesize responseBody = _responseBody; +@synthesize responseData = _responseBody; @synthesize responseString = _responseString; @synthesize totalBytesRead = _totalBytesRead; @synthesize dataAccumulator = _dataAccumulator; @@ -207,8 +207,9 @@ static inline NSString * AFKeyPathFromOperationState(AFOperationState state) { return NO; } case AFHTTPOperationFinishedState: - default: return NO; + default: + return YES; } } @@ -223,9 +224,9 @@ static inline NSString * AFKeyPathFromOperationState(AFOperationState state) { } - (NSString *)responseString { - if (!_responseString && self.response && self.responseBody) { + if (!_responseString && self.response && self.responseData) { NSStringEncoding textEncoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)self.response.textEncodingName)); - self.responseString = [[[NSString alloc] initWithData:self.responseBody encoding:textEncoding] autorelease]; + self.responseString = [[[NSString alloc] initWithData:self.responseData encoding:textEncoding] autorelease]; } return _responseString; @@ -336,7 +337,7 @@ didReceiveResponse:(NSURLResponse *)response if (self.outputStream) { [self.outputStream close]; } else { - self.responseBody = [NSData dataWithData:self.dataAccumulator]; + self.responseData = [NSData dataWithData:self.dataAccumulator]; [_dataAccumulator release]; _dataAccumulator = nil; }