Approaching a reasonable design for restructuring AFHTTPRequestOperation and subclasses

This commit is contained in:
Mattt Thompson 2011-10-05 12:36:45 -05:00
parent c0cba6748a
commit ccdc5f2d9b
10 changed files with 89 additions and 41 deletions

View file

@ -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

View file

@ -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

View file

@ -23,6 +23,11 @@
#import <Foundation/Foundation.h>
#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;

View file

@ -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];

View file

@ -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.

View file

@ -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

View file

@ -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
///---------------------------------------

View file

@ -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;

View file

@ -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;

View file

@ -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;
}