AFNetworking: Handle error globally and repeat request AFNetworking: Handle error globally and repeat request ios ios

AFNetworking: Handle error globally and repeat request


I use an alternative means for doing this with AFNetworking 2.0.

You can subclass dataTaskWithRequest:success:failure: and wrap the passed completion block with some error checking. For example, if you're working with OAuth, you could watch for a 401 error (expiry) and refresh your access token.

- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)urlRequest completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))originalCompletionHandler{    //create a completion block that wraps the original    void (^authFailBlock)(NSURLResponse *response, id responseObject, NSError *error) = ^(NSURLResponse *response, id responseObject, NSError *error)    {        NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;        if([httpResponse statusCode] == 401){            NSLog(@"401 auth error!");            //since there was an error, call you refresh method and then redo the original task            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{                //call your method for refreshing OAuth tokens.  This is an example:                [self refreshAccessToken:^(id responseObject) {                    NSLog(@"response was %@", responseObject);                    //store your new token                    //now, queue up and execute the original task                                   NSURLSessionDataTask *originalTask = [super dataTaskWithRequest:urlRequest completionHandler:originalCompletionHandler];                    [originalTask resume];                }];                                });        }else{            NSLog(@"no auth error");            originalCompletionHandler(response, responseObject, error);        }    };    NSURLSessionDataTask *task = [super dataTaskWithRequest:urlRequest completionHandler:authFailBlock];    return task;}


In the AFHTTPClient's init method register for the AFNetworkingOperationDidFinishNotification which will be posted after a request finishes.

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(HTTPOperationDidFinish:) name:AFNetworkingOperationDidFinishNotification object:nil];

In the notification handler check the status code and copy the AFHTTPRequestOperation or create a new one.

- (void)HTTPOperationDidFinish:(NSNotification *)notification {  AFHTTPRequestOperation *operation = (AFHTTPRequestOperation *)[notification object];    if (![operation isKindOfClass:[AFHTTPRequestOperation class]]) {        return;    }    if ([operation.response statusCode] == 401) {        // enqueue a new request operation here    }}

EDIT:

In general you should not need to do that and just handle the authentication with this AFNetworking method:

- (void)setAuthenticationChallengeBlock:(void (^)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge))block;


Here is the Swift implementation of user @adamup 's answer

class SessionManager:AFHTTPSessionManager{static let sharedInstance = SessionManager()override func dataTaskWithRequest(request: NSURLRequest!, completionHandler: ((NSURLResponse!, AnyObject!, NSError!) -> Void)!) -> NSURLSessionDataTask! {    var authFailBlock : (response:NSURLResponse!, responseObject:AnyObject!, error:NSError!) -> Void = {(response:NSURLResponse!, responseObject:AnyObject!, error:NSError!) -> Void in        var httpResponse = response as! NSHTTPURLResponse        if httpResponse.statusCode == 401 {            //println("auth failed")            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), { () -> Void in                self.refreshToken(){ token -> Void in                    if let tkn = token{                        var mutableRequest = request.mutableCopy() as! NSMutableURLRequest                        mutableRequest.setValue(tkn, forHTTPHeaderField: "Authorization")                        var newRequest = mutableRequest.copy() as! NSURLRequest                        var originalTask = super.dataTaskWithRequest(newRequest, completionHandler: completionHandler)                        originalTask.resume()                    }else{                        completionHandler(response,responseObject,error)                    }                }            })        }        else{            //println("no auth error")            completionHandler(response,responseObject,error)        }    }    var task = super.dataTaskWithRequest(request, completionHandler:authFailBlock )    return task}}

where refreshToken (...) is an extension method I wrote to get a new token from the server.