Autenticación AFNetworking con service web

Tener un problema que es más una consideración de layout que la del código.

Mi aplicación iOS se conecta con un service web de json. Estoy usando AFNetworking y mi problema es, básicamente, necesito que la function init (que autentica el AFHTTPClient y recupera un token) se complete por completo antes de realizar cualquier request adicional (que requiera dicho token).

A partir del código a continuación, estaría interesado en escuchar los enfoques de layout para lograr esto, preferiría mantener todas las requestes async una solución alternativa sería hacer la request en initWithHost: port: user: pass synchronous (no utilizando AFNetworking) que I Estoy consciente es una mala práctica y quiero evitar.

DCWebServiceManager.h

#import <Foundation/Foundation.h> #import "AFHTTPClient.h" @interface DCWebServiceManager : NSObject { NSString *hostServer; NSString *hostPort; NSString *hostUser; NSString *hostPass; NSString *hostToken; AFHTTPClient *httpClient; } // Designated Initialiser - (id)initWithHost:(NSString *)host port:(NSString *)port user:(NSString *)user pass:(NSString *)pass; // Instance Methods - (void)getFileList; @end 

DCWebServiceManager.m

 #import "DCWebServiceManager.h" #import "AFHTTPClient.h" #import "AFHTTPRequestOperation.h" #import "AFJSONRequestOperation.h" @implementation DCWebServiceManager - (id)initWithHost:(NSString *)host port:(NSString *)port user:(NSString *)user pass:(NSString *)pass { self = [super init]; if (self) { hostServer = host; hostPort = port; hostUser = user; hostPass = pass; NSString *apiPath = [NSString stringWithFormat:@"http://%@:%@/", hostServer, hostPort]; httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:apiPath]]; [httpClient setAuthorizationHeaderWithUsername:hostUser password:hostPass]; NSMutableURLRequest *request = [httpClient requestWithMethod:@"GET" path:@"authenticate.php" parameters:nil]; AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject){ // Do operations to parse request token to be used in // all requests going forward... // ... // ... // Results in setting: hostToken = '<PARSED_TOKEN>' NSLog(@"HostToken: >>%@<<", hostToken); } failure:^(AFHTTPRequestOperation *operation, NSError *error){ NSLog(@"ERROR: %@", operation.responseString); }]; [operation start]; } return self; } - (void)getFileList { // ************************* // The issue is here, getFileList gets called before the hostToken is retrieved.. // Make the authenticate request in initWithHost:port:user:pass a synchronous request perhaps?? // ************************* NSLog(@"IN GETFILELIST: %@", hostToken); // Results in host token being nil!!! NSString *queryString = [NSString stringWithFormat:@"?list&token=%s", hostToken]; NSMutableURLRequest *listRequest = [httpClient requestWithMethod:@"GET" path:queryString parameters:nil]; AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:listRequest success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON){ NSLog(@"SUCCESS!"); } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON){ NSLog(@"ERROR!: %@", error); }]; [operation start]; } @end 

ViewController.m

 .... DCWebServiceManager *manager = [[DCWebServiceManager alloc] initWithHost:@"localhost" port:@"23312" user:@"FOO" pass:@"BAR"]; [manager getFileList]; // OUTPUTS IN GETFILELIST: (nil) HostToken: >>sdf5fdsfs46a6cawca6<< .... ... 

Sugiero subclasificar AFHTTPClient y agregar una propiedad +shanetworkingInstance y propiedad para el token.

 + (MyGClient *)shanetworkingInstanceWithHost:(NSString *)host port:(NSString *)port user:(NSString *)user pass:(NSString *)pass { static MyClient *shanetworkingInstance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ [... your code from the init ...] }); return shanetworkingInstance; } 

A continuación, puede anular enqueueHTTPRequestOperationWithRequest:success:failure comtesting el token antes de activar otras operaciones.

Además, puede recostackr las operaciones y enqueuerlas tan pronto como se establezca el token anulando el setter para la propiedad.

Como @ patric.schenke dijo, puede subclass AFHTTPClient si desea limpiar parte de su código, pero el verdadero problema es que debe hacer otra request para autenticar (si su token es nulo) antes de hacer la request de getFileList .

Recomendaría utilizar bloques de la misma manera que AFNetworking está utilizando bloques para permanecer asíncrono. Mueva su llamada HTTP a su propio método y hostToken solo cuando su hostToken sea ​​nulo:

 - (void)getFileList { if (self.token == nil) { [self updateTokenThenWhenComplete:^(void){ // make HTTP call to get file list }]; } else { // make HTTP call to get file list } } - (void)updateTokenThenWhenComplete:(void (^))callback { //... make HTTP request [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject){ self.token = responseObject.token; callback(); } failure:^(AFHTTPRequestOperation *operation, NSError *error){ //... }]; }