Skip to content

Instantly share code, notes, and snippets.

@chrishulbert
Last active August 29, 2015 14:06
Show Gist options
  • Save chrishulbert/35ecbec4b37d36b0d608 to your computer and use it in GitHub Desktop.
Save chrishulbert/35ecbec4b37d36b0d608 to your computer and use it in GitHub Desktop.
!!! There's a better solution here now, that doesn't require swizzling:
!!! http://www.splinter.com.au/2014/09/10/afnetworking-error-bodies/
!!! But i'll leave the below swizzling solution up for old time's sake
// AFURLSessionManager+ErrorResponse.h
// This hacks AFURLSessionManager so that it returns the error response in failure callbacks, in the error's userInfo.
// Usage:
// [mySessionManager POST:@"some_api_endpoint" parameters:params success:^(NSURLSessionDataTask *task, NSDictionary *responseObject) {
// ...
// } failure:^(NSURLSessionDataTask *task, NSError *error) {
// id responseObject = error.userInfo[kErrorResponseObjectKey];
// ...
// }];
#import "AFURLSessionManager.h"
/// The NSError userInfo dictionary key for the responseObject.
#define kErrorResponseObjectKey @"kErrorResponseObjectKey"
@interface AFURLSessionManager (ErrorResponse)
@end
// AFURLSessionManager+ErrorResponse.m
#import "AFURLSessionManager+ErrorResponse.h"
#import <objc/runtime.h>
@implementation AFURLSessionManager (ErrorResponse)
#pragma mark - Hooks into the VC lifecycle
/// Wrap the completion handler with a new handler that injects the response into an error's userInfo before calling the original handler.
- (NSURLSessionDataTask *)errorResponse_dataTaskWithRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))originalCompletionHandler {
// This calls through to the original, really.
return [self errorResponse_dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
// If there's an error, store the response in it if we've got one.
if (error && responseObject) {
if (error.userInfo) { // Already has a dictionary, so we need to add to it.
NSMutableDictionary *userInfo = [error.userInfo mutableCopy];
userInfo[kErrorResponseObjectKey] = responseObject;
error = [NSError errorWithDomain:error.domain code:error.code userInfo:[userInfo copy]];
} else { // No dictionary, make a new one.
error = [NSError errorWithDomain:error.domain code:error.code userInfo:@{kErrorResponseObjectKey: responseObject}];
}
}
// Call the original handler.
if (originalCompletionHandler) {
originalCompletionHandler(response, responseObject, error);
}
}];
}
#pragma mark - Swizzling
/// Do the swizzling at load time.
+ (void)load {
ErrorResponse_MethodSwizzle(self, @selector(dataTaskWithRequest:completionHandler:), @selector(errorResponse_dataTaskWithRequest:completionHandler:));
}
/// Swizzle the method into place.
void ErrorResponse_MethodSwizzle(Class c, SEL origSEL, SEL overrideSEL) {
Method origMethod = class_getInstanceMethod(c, origSEL);
Method overrideMethod = class_getInstanceMethod(c, overrideSEL);
if (class_addMethod(c, origSEL, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod))) {
class_replaceMethod(c, overrideSEL, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
} else {
method_exchangeImplementations(origMethod, overrideMethod);
}
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment