iOS: las requestes de NSURL fallaron nuevamente en NSURLSesión

En mi aplicación, las llamadas 2-4 API a mi server pueden estar sucediendo al mismo time (de forma asíncrona) dentro de la class NSURLSession mi API. Para realizar requestes API a mi server, debo proporcionar el token de authentication en el HTTPHeaderField de cada NSURLRequest . El token es válido por un día, y si se vuelve inválido después de un día, necesito actualizar el token.

Lo hago en el siguiente código en mi class API:

 /*! * @brief sends a request as an NSHTTPURLResponse. This method is private. * @param request The request to send. * @param success A block to be called if the request is successful. * @param error A block to be called if the request fails. */ -(void)sendTask:(NSURLRequest*)request successCallback:(void (^)(NSDictionary*))success errorCallback:(void (^)(NSString*))errorCallback { NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { [self parseResponse:response data:data fromRequest:request successCallback:success errorCallback:^(NSString *error) { //if auth token expinetworking and getting "not authenticated" error (status 401) NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response; if (httpResp.statusCode == 401) { [self refreshAuthenticationTokenWithSuccessCallback:^(NSDictionary *response) { self.authToken = response[@"token"]; //attempt to re-try the request that failed due to token expiration [self sendTask:request successCallback:success errorCallback:errorCallback]; } errorCallback:^(NSString *error) { //two weeks have passed and the token is no longer refreshable NSLog(@"TOKEN NOT REFRESHABLE! HAVE TO LOG IN MANUALLY"); }]; } }]; }]; [task resume]; } 

Este método sendTask se ejecuta con cada request de API que hago en la aplicación, así que me di count de que esta es una mala forma de hacerlo. Si 3 requestes de API fallan debido a que el token no es válido (pasó un día), entonces las 3 requestes de estas API intentarán realizar la llamada de API para actualizar el token de authentication.

¿Hay alguna forma de que, en caso de que UNA de las requestes de la API falle, actualice el token de authentication solo UNA VEZ y luego vuelva a intentar las llamadas falladas de la API?

EDITAR

Edité el título de la pregunta para indicar que estoy trabajando con NSURL.

PROGRESO

Hasta ahora, para evitar que varias requestes de API fallidas traten de actualizar el token de authentication al mismo time, tengo un NSArray para todas las requestes fallidas y un NSNumber que sirve como locking para asegurarme de que el token de authentication solo está intentando ser restaurado una vez Hago esto en el siguiente código:

 -(void)sendTask:(NSURLRequest*)request successCallback:(void (^)(NSDictionary*))success errorCallback:(void (^)(NSString*))errorCallback { NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { MyAPIInterface *__weak weakSelf = self; [self parseResponse:response data:data fromRequest:request successCallback:success errorCallback:^(NSString *error) { NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response; if (httpResp.statusCode == 401) { if ([error isEqualToString:@"invalid_cnetworkingentials"]) { errorCallback(@"Invalid username and/or password"); } else if ([error isEqualToString:@"Unknown error"]) { errorCallback(error); } else { if (!weakSelf.alreadyRefreshingToken.boolValue) { //lock alreadyRefreshingToken boolean weakSelf.alreadyRefreshingToken = [NSNumber numberWithBool:YES]; NSLog(@"NOT REFRESHING TOKEN"); // add failed request to failedRequests array NSMutableArray *mutableFailedRequests = [weakSelf.failedRequests mutableCopy]; [mutableFailedRequests addObject:request]; weakSelf.failedRequests = [mutableFailedRequests copy]; // refresh auth token [weakSelf refreshAuthenticationTokenWithSuccessCallback:^(NSDictionary *response) { //store authToken weakSelf.authToken = response[@"token"]; NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; [defaults setObject:weakSelf.authToken forKey:@"authToken"]; [defaults synchronize]; //attempt to re-try all requests that failed due to token expiration for (NSURLRequest *failedRequest in weakSelf.failedRequests) { [weakSelf sendTask:failedRequest successCallback:success errorCallback:errorCallback]; } //clear failedRequests array and unlock alreadyRefreshingToken boolean [weakSelf clearFailedRequests]; weakSelf.alreadyRefreshingToken = [NSNumber numberWithBool:NO]; NSLog(@"TOKEN REFRESHING SUCCESSFUL THO"); } errorCallback:^(NSString *error) { NSLog(@"TOKEN NOT REFRESHABLE! HAVE TO LOG IN MANUALLY"); //clear failedRequests array [weakSelf clearFailedRequests]; errorCallback(@"Your login session has expinetworking"); }]; } else { NSLog(@"ALREADY REFRESHING TOKEN. JUST ADD TO FAILED LIST"); NSMutableArray *mutableFailedRequests = [weakSelf.failedRequests mutableCopy]; [mutableFailedRequests addObject:request]; weakSelf.failedRequests = [mutableFailedRequests copy]; } } } else { NSLog(@"ERROR STRING THO: %@", error); errorCallback(error); } }]; }]; [task resume]; } #pragma mark Custom Methods -(void)clearFailedRequests { NSMutableArray *mutableFailedRequests = [self.failedRequests mutableCopy]; [mutableFailedRequests removeAllObjects]; self.failedRequests = [mutableFailedRequests copy]; } 

¿Lo estoy haciendo correctamente? Una parte de la cual soy paranoico es que realmente no estoy llamando al success o al error callback en ciertos puntos. ¿Esto puede llevar a problemas?

En lugar de usar [self sendTask:], intente con [weakSelf sendTask]. Consulte el siguiente código:

 -(void)sendTask:(NSURLRequest*)request successCallback:(void (^)(NSDictionary*))success errorCallback:(void (^)(NSString*))errorCallback { __weak __typeof(self)weakSelf = self; NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { [self parseResponse:response data:data fromRequest:request successCallback:success errorCallback:^(NSString *error) { //if auth token expinetworking and getting "not authenticated" error (status 401) NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response; if (httpResp.statusCode == 401) { [self refreshAuthenticationTokenWithSuccessCallback:^(NSDictionary *response) { self.authToken = response[@"token"]; //attempt to re-try the request that failed due to token expiration [weakSelf sendTask:request successCallback:success errorCallback:errorCallback]; } errorCallback:^(NSString *error) { //two weeks have passed and the token is no longer refreshable NSLog(@"TOKEN NOT REFRESHABLE! HAVE TO LOG IN MANUALLY"); }]; } }]; }]; [task resume]; }