Pour donner un peu de context: J'essaye d'implémenter un gestionnaire d'erreur global pour les erreurs d'authentification (en utilisant l'authentification par jeton, pas basique), qui devrait essayer de s'authentifier à nouveau et de refaire la request d'origine (voir ma question précédente: AFNetworking: Handle erreur globalement et request de répétition )
L'approche actuelle consiste à save un observateur pour l' AFNetworkingOperationDidFinishNotification
qui effectue la ré-authentification et (si auth réussi) répète la requête d'origine:
- (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]; // copys 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? } ]; } }
Cependant, je suis tombé sur quelques problèmes concernant les blocs d'achèvement des opérations de requête:
En répétant la requête d'origine, je veux évidemment que ses blocs d'achèvement soient exécutés. Cependant, AFHTTPRequestOperation
ne conserve pas les references aux blocs succès et échec passés (voir setCompletionBlockWithSuccess:failure:
NSOperation
et la copy de NSOperation
de NSOperation
n'est probablement pas une bonne idée, car la documentation de AFURLConnectionOperation
indique:
Les copys d'opération n'incluent pas
completionBlock
.completionBlock
capture souvent fortement une reference àself
–self
, ce qui, peut-être étonnamment, indiquerait l'opération d' origine lors de la copy.
En cas d'échec de la ré-authentification, je souhaite appeler le bloc d'échec de la requête d'origine. Donc, encore une fois, j'aurais besoin d'un access direct à cela.
Est-ce que j'ai râté quelque chose? Des idées pour des approches alternatives? Dois-je déposer une request de fonctionnalité?
J'ai trouvé ce problème dans l'application Portfolio d' Art.sy . Ma conclusion éventuelle était de créer une sous-class NSOperationQueue qui avait des fonctions pour créer des copys de diverses opérations HTTP AFNetworking une fois qu'elles ont échoué (et pour faire cela jusqu'à trois fois par URL avant d'abandonner.)
Avez-vous essayé ce qui suit?
// set success / failure block of original operation [newOperation setCompletionBlock:[operation.completionBlock copy]]; [operation setCompletionBlock:nil];
Notez que si vous capturez self dans les blocs d'achèvement / d'échec d'origine (c.-à-d. Accédez à des ivars), vous accédez réellement à l'instance d'opération d'origine lors de l'exécution du bloc d'achèvement de newOperation. Mais c'est ce que vous voulez réellement, non?
Le gestionnaire de notification est exécuté avant le bloc d'achèvement de l'opération. Vous devez donc définir le bloc d'achèvement de l'opération d'origine sur zéro, pour l'empêcher d'être exécuté deux fois.
Notez que le bloc d'achèvement est défini sur zéro après son exécution (voir AFURLConnectionOperation).
Dans le bloc d'échec authenticateWithCredentials, vous ne devez rien faire. L'opération d'origine s'est terminée à ce moment et a déjà exécuté son bloc de défaillance.