AFNetworking: acceso a controlleres de finalización cuando reintenta la operación

Para dar un poco de context: bash implementar un controller de errores global para errores de authentication (utilizando authentication de token, no básico), que debería intentar volver a autenticarse y luego repetir la request fallida original (ver mi pregunta anterior: AFNetworking: Handle error global y request de repetición )

El enfoque actual es registrar un observador para AFNetworkingOperationDidFinishNotification que hace la authentication y (si la authentication fue exitosa) repite la request original:

 - (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 shanetworkingUserManager] authenticateWithCnetworkingentials... 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? } ]; } } 

Sin embargo, tropecé con algunos problemas relacionados con los bloques de finalización de las operaciones de request:

  • Al repetir la request original, obviamente quiero que se ejecuten sus bloques de finalización. Sin embargo, AFHTTPRequestOperation no conserva references al éxito pasado y los bloques de fallas (ver setCompletionBlockWithSuccess:failure: NSOperation y copyr el completionBlock NSOperation probablemente no sea una buena idea, ya que la documentation para AFURLConnectionOperation indica:

    Las copys de operación no incluyen completionBlock . completionBlock menudo captura fuertemente una reference a self , lo que, tal vez sorprendentemente, de lo contrario apuntaría a la operación original cuando se copy.

  • En caso de que la authentication vuelva a fallar, quiero llamar al bloque de fallas de la request original. Entonces, nuevamente, necesitaría acceso directo a esto.

¿Me estoy perdiendo de algo? ¿Alguna idea para enfoques alternativos? ¿Debo presentar una request de function?

Se me ocurrió este problema en la aplicación de cartera de Art.sy. Mi conclusión final fue crear una subclass NSOperationQueue que tenía funciones para crear copys de varias operaciones HTTP AFNetworking una vez que falló (y hacer esto hasta tres veces por URL antes de darse por vencido).

¿Probaste lo siguiente?

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

Tenga en count que si captura uno mismo en los bloques originales de finalización / falla (es decir, accede a cualquier ivars), accederá realmente a la instancia de operación original cuando ejecute el bloque de finalización de la nueva operación. Pero esto es lo que quieres en realidad, ¿verdad?

El manejador de notifications se ejecuta antes del bloque de finalización de la operación. Por lo tanto, debe configurar el bloque de finalización de la operación original en cero, para evitar que se ejecute dos veces.

Tenga en count que el bloque de finalización se establece en cero después de ejecutarse (consulte AFURLConnectionOperation).

En el bloque de falla authenticateWithCnetworkingentials no deberías hacer nada. La operación original ha finalizado en ese momento y ya ha ejecutado su bloque de fallas.