AFNetworking: Access to completion handlers when retrying operation

 ̄綄美尐妖づ 提交于 2019-12-22 05:07:18

问题


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?


回答1:


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.)




回答2:


Did you try the following?

// set success / failure block of original operation
[newOperation setCompletionBlock:[operation.completionBlock copy]];
[operation setCompletionBlock:nil];

Note that if you capture self in the original completion/failure blocks (i.e. access any ivars) you actually access the original operation instance when executing the completion block of the newOperation. But this is what you want actually, right?

The notification handler is executed before the completion block of the operation. So you should set the completion block of the original operation to nil, to prevent it from executing twice.

Note the completion block is set to nil after it has executed (see AFURLConnectionOperation).

In the authenticateWithCredentials failure block you should not do anything. The original operation has finished at that time and already has executed its failure block.



来源:https://stackoverflow.com/questions/12951037/afnetworking-access-to-completion-handlers-when-retrying-operation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!