When switched to AFNetworking 2.0 the AFHTTPClient has been replaced by AFHTTPRequestOperationManager / AFHTTPSessionManager (as mentioned in the migration guide). The very
After of read and research for several days, It worked for me:
1) You have to build your own subclass of AFJSONResponseSerializer
File : JSONResponseSerializerWithData.h:
#import "AFURLResponseSerialization.h"
/// NSError userInfo key that will contain response data
static NSString * const JSONResponseSerializerWithDataKey = @"JSONResponseSerializerWithDataKey";
@interface JSONResponseSerializerWithData : AFJSONResponseSerializer
@end
File: JSONResponseSerializerWithData.m
#import "JSONResponseSerializerWithData.h"
@implementation JSONResponseSerializerWithData
- (id)responseObjectForResponse:(NSURLResponse *)response
data:(NSData *)data
error:(NSError *__autoreleasing *)error
{
id JSONObject = [super responseObjectForResponse:response data:data error:error];
if (*error != nil) {
NSMutableDictionary *userInfo = [(*error).userInfo mutableCopy];
if (data == nil) {
// // NOTE: You might want to convert data to a string here too, up to you.
// userInfo[JSONResponseSerializerWithDataKey] = @"";
userInfo[JSONResponseSerializerWithDataKey] = [NSData data];
} else {
// // NOTE: You might want to convert data to a string here too, up to you.
// userInfo[JSONResponseSerializerWithDataKey] = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
userInfo[JSONResponseSerializerWithDataKey] = data;
}
NSError *newError = [NSError errorWithDomain:(*error).domain code:(*error).code userInfo:userInfo];
(*error) = newError;
}
return (JSONObject);
}
2) Setup your own JSONResponseSerializer in your AFHTTPSessionManager
+ (instancetype)sharedManager
{
static CustomSharedManager *manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[CustomSharedManager alloc] initWithBaseURL:<# your base URL #>];
// *** Use our custom response serializer ***
manager.responseSerializer = [JSONResponseSerializerWithData serializer];
});
return (manager);
}
Source: http://blog.gregfiumara.com/archives/239
You can access the “data” object directly from AFNetworking by using the “AFNetworkingOperationFailingURLResponseDataErrorKey” key so there is no need for subclassing the AFJSONResponseSerializer. You can the serialize the data into a readable dictionary. Here is some sample code to get JSON Data :
NSData *errorData = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey];
NSDictionary *serializedData = [NSJSONSerialization JSONObjectWithData: errorData options:kNilOptions error:nil];
Here is the code to Get Status code in the Failure block:
NSHTTPURLResponse* r = (NSHTTPURLResponse*)task.response;
NSLog( @"success: %d", r.statusCode );
You can get the userInfo
dictionary associated with the NSError
object and traverse down that to get the exact response you need. For example in my case I get an error from a server and I can see the userInfo
like in ScreeShot
You can get the status code like this, read the failure block...
NSURLSessionDataTask *op = [[IAClient sharedClient] POST:path parameters:paramsDict constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
} success:^(NSURLSessionDataTask *task, id responseObject) {
DLog(@"\n============= Entity Saved Success ===\n%@",responseObject);
completionBlock(responseObject, nil);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
DLog(@"\n============== ERROR ====\n%@",error.userInfo);
NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
int statuscode = response.statusCode;}
In Swift 2.0 (in case you cannot use Alamofire yet):
Get status code:
if let response = error.userInfo[AFNetworkingOperationFailingURLResponseErrorKey] as? NSHTTPURLResponse {
print(response.statusCode)
}
Get response data:
if let data = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] as? NSData {
print("\(data.length)")
}
Some JSON REST APIs return error messages in their error responses (Amazon AWS services for example). I use this function to extract the error message from an NSError that has been thrown by AFNetworking:
// Example: Returns string "error123" for JSON { message: "error123" }
func responseMessageFromError(error: NSError) -> String? {
do {
guard let data = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] as? NSData else {
return nil
}
guard let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) as? [String: String] else {
return nil
}
if let message = json["message"] {
return message
}
return nil
} catch {
return nil
}
}
You can access the “data” object directly from AFNetworking by using the “AFNetworkingOperationFailingURLResponseDataErrorKey” key so there is no need for subclassing the AFJSONResponseSerializer. You can the serialize the data into a readable dictionary. Here is some sample code :
NSData *errorData = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey];
NSDictionary *serializedData = [NSJSONSerialization JSONObjectWithData: errorData options:kNilOptions error:nil];