Using NSJSONSerializer when supported, falling back on JSONKit

Changing return type for JSON response from NSDictionary to id, to support non-dictionary top-level elements in response, such as arrays

Defining default acceptable content types and status codes as class methods in AFJSONRequestOperation

Adding text/json to acceptable MIME type for JSON
This commit is contained in:
Mattt Thompson 2011-08-03 11:31:00 -05:00
parent f169a93f58
commit 68dc7e866e
5 changed files with 81 additions and 51 deletions

View file

@ -42,7 +42,6 @@ static inline NSString * AFKeyPathFromOperationState(AFHTTPOperationState state)
case AFHTTPOperationExecutingState: case AFHTTPOperationExecutingState:
return @"isExecuting"; return @"isExecuting";
case AFHTTPOperationFinishedState: case AFHTTPOperationFinishedState:
case AFHTTPOperationCancelledState:
return @"isFinished"; return @"isFinished";
default: default:
return @"state"; return @"state";
@ -58,7 +57,6 @@ static inline BOOL AFHTTPOperationStateTransitionIsValid(AFHTTPOperationState fr
case AFHTTPOperationReadyState: case AFHTTPOperationReadyState:
switch (to) { switch (to) {
case AFHTTPOperationExecutingState: case AFHTTPOperationExecutingState:
case AFHTTPOperationCancelledState:
return YES; return YES;
default: default:
return NO; return NO;
@ -71,7 +69,6 @@ static inline BOOL AFHTTPOperationStateTransitionIsValid(AFHTTPOperationState fr
return YES; return YES;
} }
case AFHTTPOperationFinishedState: case AFHTTPOperationFinishedState:
case AFHTTPOperationCancelledState:
return NO; return NO;
default: default:
return YES; return YES;
@ -80,13 +77,17 @@ static inline BOOL AFHTTPOperationStateTransitionIsValid(AFHTTPOperationState fr
@interface AFHTTPRequestOperation () @interface AFHTTPRequestOperation ()
@property (nonatomic, assign) AFHTTPOperationState state; @property (nonatomic, assign) AFHTTPOperationState state;
@property (nonatomic, assign) BOOL isCancelled;
@property (readwrite, nonatomic, retain) NSPort *port; @property (readwrite, nonatomic, retain) NSPort *port;
@property (readwrite, nonatomic, retain) NSMutableData *dataAccumulator; @property (readwrite, nonatomic, retain) NSMutableData *dataAccumulator;
@property (readwrite, nonatomic, copy) AFHTTPRequestOperationCompletionBlock completion; @property (readwrite, nonatomic, copy) AFHTTPRequestOperationCompletionBlock completion;
- (void)cleanup;
@end @end
@implementation AFHTTPRequestOperation @implementation AFHTTPRequestOperation
@synthesize state = _state; @synthesize state = _state;
@synthesize isCancelled = _isCancelled;
@synthesize connection = _connection; @synthesize connection = _connection;
@synthesize runLoopModes = _runLoopModes; @synthesize runLoopModes = _runLoopModes;
@synthesize port = _port; @synthesize port = _port;
@ -136,6 +137,14 @@ static inline BOOL AFHTTPOperationStateTransitionIsValid(AFHTTPOperationState fr
[super dealloc]; [super dealloc];
} }
- (void)cleanup {
for (NSString *runLoopMode in self.runLoopModes) {
[[NSRunLoop currentRunLoop] removePort:self.port forMode:runLoopMode];
[self.connection unscheduleFromRunLoop:[NSRunLoop currentRunLoop] forMode:runLoopMode];
}
CFRunLoopStop([[NSRunLoop currentRunLoop] getCFRunLoop]);
}
- (void)setState:(AFHTTPOperationState)state { - (void)setState:(AFHTTPOperationState)state {
if (!AFHTTPOperationStateTransitionIsValid(self.state, state)) { if (!AFHTTPOperationStateTransitionIsValid(self.state, state)) {
return; return;
@ -156,15 +165,9 @@ static inline BOOL AFHTTPOperationStateTransitionIsValid(AFHTTPOperationState fr
[[NSNotificationCenter defaultCenter] postNotificationName:AFHTTPOperationDidStartNotification object:self]; [[NSNotificationCenter defaultCenter] postNotificationName:AFHTTPOperationDidStartNotification object:self];
break; break;
case AFHTTPOperationFinishedState: case AFHTTPOperationFinishedState:
case AFHTTPOperationCancelledState:
[[AFNetworkActivityIndicatorManager sharedManager] stopAnimating]; [[AFNetworkActivityIndicatorManager sharedManager] stopAnimating];
[[NSNotificationCenter defaultCenter] postNotificationName:AFHTTPOperationDidFinishNotification object:self]; [[NSNotificationCenter defaultCenter] postNotificationName:AFHTTPOperationDidFinishNotification object:self];
[self cleanup];
for (NSString *runLoopMode in self.runLoopModes) {
[[NSRunLoop currentRunLoop] removePort:self.port forMode:runLoopMode];
[self.connection unscheduleFromRunLoop:[NSRunLoop currentRunLoop] forMode:runLoopMode];
}
CFRunLoopStop([[NSRunLoop currentRunLoop] getCFRunLoop]);
break; break;
default: default:
break; break;
@ -186,11 +189,7 @@ static inline BOOL AFHTTPOperationStateTransitionIsValid(AFHTTPOperationState fr
} }
- (BOOL)isFinished { - (BOOL)isFinished {
return self.state == AFHTTPOperationFinishedState || self.isCancelled; return self.state == AFHTTPOperationFinishedState || [self isCancelled];
}
- (BOOL)isCancelled {
return self.state == AFHTTPOperationCancelledState;
} }
- (BOOL)isConcurrent { - (BOOL)isConcurrent {
@ -219,9 +218,11 @@ static inline BOOL AFHTTPOperationStateTransitionIsValid(AFHTTPOperationState fr
} }
- (void)cancel { - (void)cancel {
self.state = AFHTTPOperationCancelledState; self.isCancelled = YES;
[self.connection cancel]; [self.connection cancel];
[self cleanup];
} }
#pragma mark - AFHTTPRequestOperation #pragma mark - AFHTTPRequestOperation
@ -266,4 +267,12 @@ static inline BOOL AFHTTPOperationStateTransitionIsValid(AFHTTPOperationState fr
[self performSelectorOnMainThread:@selector(finish) withObject:nil waitUntilDone:YES modes:[self.runLoopModes allObjects]]; [self performSelectorOnMainThread:@selector(finish) withObject:nil waitUntilDone:YES modes:[self.runLoopModes allObjects]];
} }
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
if ([self isCancelled]) {
return nil;
}
return cachedResponse;
}
@end @end

View file

@ -25,16 +25,19 @@
@interface AFJSONRequestOperation : AFHTTPRequestOperation @interface AFJSONRequestOperation : AFHTTPRequestOperation
+ (id)operationWithRequest:(NSURLRequest *)urlRequest + (id)operationWithRequest:(NSURLRequest *)urlRequest
success:(void (^)(NSDictionary *JSON))success; success:(void (^)(id JSON))success;
+ (id)operationWithRequest:(NSURLRequest *)urlRequest + (id)operationWithRequest:(NSURLRequest *)urlRequest
success:(void (^)(NSDictionary *JSON))success success:(void (^)(id JSON))success
failure:(void (^)(NSError *error))failure; failure:(void (^)(NSError *error))failure;
+ (id)operationWithRequest:(NSURLRequest *)urlRequest + (id)operationWithRequest:(NSURLRequest *)urlRequest
acceptableStatusCodes:(NSIndexSet *)acceptableStatusCodes acceptableStatusCodes:(NSIndexSet *)acceptableStatusCodes
acceptableContentTypes:(NSSet *)acceptableContentTypes acceptableContentTypes:(NSSet *)acceptableContentTypes
success:(void (^)(NSDictionary *JSON))success success:(void (^)(id JSON))success
failure:(void (^)(NSError *error))failure; failure:(void (^)(NSError *error))failure;
+ (NSIndexSet *)defaultAcceptableStatusCodes;
+ (NSSet *)defaultAcceptableContentTypes;
@end @end

View file

@ -26,25 +26,22 @@
@implementation AFJSONRequestOperation @implementation AFJSONRequestOperation
+ (id)operationWithRequest:(NSURLRequest *)urlRequest + (id)operationWithRequest:(NSURLRequest *)urlRequest
success:(void (^)(NSDictionary *JSON))success success:(void (^)(id JSON))success
{ {
return [self operationWithRequest:urlRequest success:success failure:nil]; return [self operationWithRequest:urlRequest success:success failure:nil];
} }
+ (id)operationWithRequest:(NSURLRequest *)urlRequest + (id)operationWithRequest:(NSURLRequest *)urlRequest
success:(void (^)(NSDictionary *JSON))success success:(void (^)(id JSON))success
failure:(void (^)(NSError *error))failure failure:(void (^)(NSError *error))failure
{ {
NSIndexSet *acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)]; return [self operationWithRequest:urlRequest acceptableStatusCodes:[self defaultAcceptableStatusCodes] acceptableContentTypes:[self defaultAcceptableContentTypes] success:success failure:failure];
NSSet *acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"application/x-javascript", @"text/javascript", @"text/x-javascript", @"text/x-json", @"text/plain", nil];
return [self operationWithRequest:urlRequest acceptableStatusCodes:acceptableStatusCodes acceptableContentTypes:acceptableContentTypes success:success failure:failure];
} }
+ (id)operationWithRequest:(NSURLRequest *)urlRequest + (id)operationWithRequest:(NSURLRequest *)urlRequest
acceptableStatusCodes:(NSIndexSet *)acceptableStatusCodes acceptableStatusCodes:(NSIndexSet *)acceptableStatusCodes
acceptableContentTypes:(NSSet *)acceptableContentTypes acceptableContentTypes:(NSSet *)acceptableContentTypes
success:(void (^)(NSDictionary *JSON))success success:(void (^)(id JSON))success
failure:(void (^)(NSError *error))failure failure:(void (^)(NSError *error))failure
{ {
return [self operationWithRequest:urlRequest completion:^(NSURLRequest *request, NSHTTPURLResponse *response, NSData *data, NSError *error) { return [self operationWithRequest:urlRequest completion:^(NSURLRequest *request, NSHTTPURLResponse *response, NSData *data, NSError *error) {
@ -63,13 +60,34 @@
failure(error); failure(error);
} }
} else { } else {
NSDictionary *JSON = [[JSONDecoder decoder] objectWithData:data error:&error]; id JSON = nil;
if (success) { Class NSJSONSerialization = NSClassFromString(@"NSJSONSerialization");
success(JSON); if (NSJSONSerialization) {
JSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
} else {
JSON = [[JSONDecoder decoder] objectWithData:data error:&error];
}
if (error) {
if (failure) {
failure(error);
}
} else {
if (success) {
success(JSON);
}
} }
} }
}]; }];
} }
+ (NSIndexSet *)defaultAcceptableStatusCodes {
return [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];
}
+ (NSSet *)defaultAcceptableContentTypes {
return [NSSet setWithObjects:@"application/json", @"application/x-javascript", @"text/javascript", @"text/x-javascript", @"text/x-json", @"text/json", @"text/plain", nil];
}
@end @end

View file

@ -39,19 +39,19 @@
- (void)clearAuthorizationHeader; - (void)clearAuthorizationHeader;
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters; - (NSMutableURLRequest *)requestWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters;
- (void)enqueueHTTPOperationWithRequest:(NSURLRequest *)request success:(void (^)(NSDictionary *response))success failure:(void (^)(NSError *error))failure; - (void)enqueueHTTPOperationWithRequest:(NSURLRequest *)request success:(void (^)(id response))success failure:(void (^)(NSError *error))failure;
- (void)getPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(NSDictionary *response))success; - (void)getPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(id response))success;
- (void)getPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(NSDictionary *response))success failure:(void (^)(NSError *error))failure; - (void)getPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(id response))success failure:(void (^)(NSError *error))failure;
- (void)postPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(NSDictionary *response))success; - (void)postPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(id response))success;
- (void)postPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(NSDictionary *response))success failure:(void (^)(NSError *error))failure; - (void)postPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(id response))success failure:(void (^)(NSError *error))failure;
- (void)putPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(NSDictionary *response))success; - (void)putPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(id response))success;
- (void)putPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(NSDictionary *response))success failure:(void (^)(NSError *error))failure; - (void)putPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(id response))success failure:(void (^)(NSError *error))failure;
- (void)deletePath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(NSDictionary *response))success; - (void)deletePath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(id response))success;
- (void)deletePath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(NSDictionary *response))success failure:(void (^)(NSError *error))failure; - (void)deletePath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(id response))success failure:(void (^)(NSError *error))failure;
@end @end
#pragma mark - NSString + AFRestClient #pragma mark - NSString + AFRestClient

View file

@ -29,7 +29,7 @@ static NSStringEncoding const kAFRestClientStringEncoding = NSUTF8StringEncoding
@property (readwrite, nonatomic, retain) NSMutableDictionary *defaultHeaders; @property (readwrite, nonatomic, retain) NSMutableDictionary *defaultHeaders;
@property (readwrite, nonatomic, retain) NSOperationQueue *operationQueue; @property (readwrite, nonatomic, retain) NSOperationQueue *operationQueue;
- (void)enqueueHTTPOperationWithRequest:(NSURLRequest *)request success:(void (^)(NSDictionary *response))success failure:(void (^)(NSError *error))failure; - (void)enqueueHTTPOperationWithRequest:(NSURLRequest *)request success:(void (^)(id response))success failure:(void (^)(NSError *error))failure;
@end @end
@implementation AFRestClient @implementation AFRestClient
@ -128,7 +128,7 @@ static NSStringEncoding const kAFRestClientStringEncoding = NSUTF8StringEncoding
return request; return request;
} }
- (void)enqueueHTTPOperationWithRequest:(NSURLRequest *)request success:(void (^)(NSDictionary *response))success failure:(void (^)(NSError *error))failure { - (void)enqueueHTTPOperationWithRequest:(NSURLRequest *)request success:(void (^)(id response))success failure:(void (^)(NSError *error))failure {
if ([request URL] == nil || [[request URL] isEqual:[NSNull null]]) { if ([request URL] == nil || [[request URL] isEqual:[NSNull null]]) {
return; return;
} }
@ -137,38 +137,38 @@ static NSStringEncoding const kAFRestClientStringEncoding = NSUTF8StringEncoding
[self.operationQueue addOperation:operation]; [self.operationQueue addOperation:operation];
} }
- (void)getPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(NSDictionary *))success { - (void)getPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(id response))success {
[self getPath:path parameters:parameters success:success failure:nil]; [self getPath:path parameters:parameters success:success failure:nil];
} }
- (void)getPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(NSDictionary *))success failure:(void (^)(NSError *error))failure { - (void)getPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(id response))success failure:(void (^)(NSError *error))failure {
NSURLRequest *request = [self requestWithMethod:@"GET" path:path parameters:parameters]; NSURLRequest *request = [self requestWithMethod:@"GET" path:path parameters:parameters];
[self enqueueHTTPOperationWithRequest:request success:success failure:failure]; [self enqueueHTTPOperationWithRequest:request success:success failure:failure];
} }
- (void)postPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(NSDictionary *))success { - (void)postPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(id response))success {
[self postPath:path parameters:parameters success:success failure:nil]; [self postPath:path parameters:parameters success:success failure:nil];
} }
- (void)postPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(NSDictionary *))success failure:(void (^)(NSError *error))failure { - (void)postPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(id response))success failure:(void (^)(NSError *error))failure {
NSURLRequest *request = [self requestWithMethod:@"POST" path:path parameters:parameters]; NSURLRequest *request = [self requestWithMethod:@"POST" path:path parameters:parameters];
[self enqueueHTTPOperationWithRequest:request success:success failure:failure]; [self enqueueHTTPOperationWithRequest:request success:success failure:failure];
} }
- (void)putPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(NSDictionary *))success { - (void)putPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(id response))success {
[self putPath:path parameters:parameters success:success failure:nil]; [self putPath:path parameters:parameters success:success failure:nil];
} }
- (void)putPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(NSDictionary *))success failure:(void (^)(NSError *error))failure { - (void)putPath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(id response))success failure:(void (^)(NSError *error))failure {
NSURLRequest *request = [self requestWithMethod:@"PUT" path:path parameters:parameters]; NSURLRequest *request = [self requestWithMethod:@"PUT" path:path parameters:parameters];
[self enqueueHTTPOperationWithRequest:request success:success failure:failure]; [self enqueueHTTPOperationWithRequest:request success:success failure:failure];
} }
- (void)deletePath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(NSDictionary *))success { - (void)deletePath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(id response))success {
[self deletePath:path parameters:parameters success:success failure:nil]; [self deletePath:path parameters:parameters success:success failure:nil];
} }
- (void)deletePath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(NSDictionary *))success failure:(void (^)(NSError *error))failure { - (void)deletePath:(NSString *)path parameters:(NSDictionary *)parameters success:(void (^)(id response))success failure:(void (^)(NSError *error))failure {
NSURLRequest *request = [self requestWithMethod:@"DELETE" path:path parameters:parameters]; NSURLRequest *request = [self requestWithMethod:@"DELETE" path:path parameters:parameters];
[self enqueueHTTPOperationWithRequest:request success:success failure:failure]; [self enqueueHTTPOperationWithRequest:request success:success failure:failure];
} }