Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AFNetworking: Access to completion handlers when retrying operation

To give some context: I'm trying to implement a global error handler for authentication errors (using token authentication, not basic), which should try to re-authenticate and then repeat the original failed request (see my previous question: AFNetworking: Handle error globally and repeat request)

The current approach is to register an observer for the AFNetworkingOperationDidFinishNotification which does the re-authentication and (if auth succeeded) repeats the original request:

- (void)operationDidFinish:(NSNotification *)notification
{
    AFHTTPRequestOperation *operation = (AFHTTPRequestOperation *)[notification object];

    if(![operation isKindOfClass:[AFHTTPRequestOperation class]]) {
        return;
    }

    if(403 == [operation.response statusCode]) {
        // try to re-authenticate and repeat the original request
        [[UserManager sharedUserManager] authenticateWithCredentials...
            success:^{
                // repeat original request

                // AFHTTPRequestOperation *newOperation = [operation copy]; // copies too much stuff, eg. response (although the docs suggest otherwise)
                AFHTTPRequestOperation *newOperation = [[AFHTTPRequestOperation alloc] initWithRequest:operation.request];

                // PROBLEM 1: newOperation has no completion blocks. How to use the original success/failure blocks here?

                [self enqueueHTTPRequestOperation:newOperation];
            }
            failure:^(NSError *error) {
                // PROBLEM 2: How to invoke failure block of original operation?
            }
        ];
    }
}

However, I stumbled upon some issues regarding completion blocks of request operations:

  • When repeating the original request, I obviously want its completion blocks to be executed. However, AFHTTPRequestOperation does not retain references to the passed success and failure blocks (see setCompletionBlockWithSuccess:failure:) and copying NSOperation's completionBlock is probably not a good idea, as the documentation for AFURLConnectionOperation states:

    Operation copies do not include completionBlock. completionBlock often strongly captures a reference to self, which, perhaps surprisingly, would otherwise point to the original operation when copied.

  • In case the re-authentication fails, I want to call the original request's failure block. So, again, I'd need direct access to this.

Am I missing something here? Any ideas for alternative approaches? Should I file a feature request?

like image 440
Daniel Rinser Avatar asked Oct 18 '12 09:10

Daniel Rinser


1 Answers

I've come up with this problem in Art.sy's portfolio app. My eventual conclusion was to create a NSOperationQueue subclass which had functions to create copies of various AFNetworking HTTP Operations once they failed (and to do this up to three times per URL before giving up.)

like image 175
orta Avatar answered Oct 20 '22 01:10

orta