Conversión de ASIHTTPRequest a AFNetworking

Estoy convirtiendo las rutinas de mi aplicación desde ASIHTTP a AFNetworking debido a la interrupción desafortunada del trabajo en ese proyecto … y lo que luego descubrí fue la mejor y más pequeña base de código de AFNetworking.

Estoy encontrando varios problemas. Mi código para ASIHTTPRequest se crea como un método. Este método toma algunos parameters y publica los parameters en una url … devolviendo los datos resultantes. Estos datos son siempre de text, pero en aras de hacer un método genérico, a veces puede ser json, a veces XML o, a veces, HTML. Por lo tanto, construí este método como un generador de URLs independiente.

Mi problema es que cuando se llama a la rutina tengo que esperar una respuesta. Sé que todos los arguments "síncronos son malos" por ahí … y no lo hago mucho … pero para algunos methods quiero sincronizar.

Ésta es mi pregunta. Mi código simplificado ASIHTTP está a continuación, seguido de la única forma en que podría pensar en codificar esto en AFNetworking. El problema que tengo es que AFNetworking a veces no responde antes de regresar del método. La sugerencia que @mattt dio de [operation waitUntilFinished] falla totalmente en mantener el hilo hasta que se llama al bloque de finalización … y mi otro método de [queue waitUntilAllOperationsAreFinished] no siempre funciona siempre (y NO provoca el desencadenamiento del error parte de la cláusula [operation hasAcceptableStatusCode]). Por lo tanto, si alguien puede ayudar, SIN el "layout siempre asíncrono", hágalo.

Versión ASIHTTP:

 - (NSString *) queryChatSystem:(NSMutableDictionary *) theDict { NSString *response = [NSString stringWithString:@""]; NSString *theUrlString = [NSString stringWithFormat:@"%@%@",kDataDomain,kPathToChatScript]; ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:theUrlString]]; for (id key in theDict) { [request setPostValue:[theDict objectForKey:key] forKey:key]; } [request setNumberOfTimesToRetryOnTimeout:3]; [request setAllowCompressedResponse:YES]; [request startSynchronous]; NSError *error = [request error]; if (! error) { response = [request responseString]; } return response; } 

Versión AFNetworking

 - (NSString *) af_queryChatSystem:(NSMutableDictionary *) theDict { NSMutableDictionary *theParams = [NSMutableDictionary dictionaryWithCapacity:1]; for (id key in theDict) { [theParams setObject:[theDict objectForKey:key] forKey:key]; } AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:kDataDomain]]; NSMutableURLRequest *theRequest = [httpClient requestWithMethod:@"POST" path:[NSString stringWithFormat:@"/%@",kPathToChatScript] parameters:theParams]; __block NSString *responseString = [NSString stringWithString:@""]; AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc] initWithRequest:theRequest] autorelease]; operation.completionBlock = ^ { if ([operation hasAcceptableStatusCode]) { responseString = [operation responseString]; NSLog(@"hasAcceptableStatusCode: %@",responseString); } else { NSLog(@"[Error]: (%@ %@) %@", [operation.request HTTPMethod], [[operation.request URL] relativePath], operation.error); } }; NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease]; [queue addOperation:operation]; [queue waitUntilAllOperationsAreFinished]; [httpClient release]; return responseString; } 

Muchas gracias por cualquier idea.

 - (void)af_queryChatSystem:(NSMutableDictionary *) theDict block:(void (^)(NSString *string))block { ... } 

Ahora, dentro de completionBlock, haga lo siguiente:

 block(operation.responseString); 

El bloque actuará como delegado para la operación. retirar

 -waitUntilAllOperationsAreFinished 

y

 return responseString 

Llamas a esto como:

 [YourInstance af_queryChatSystem:Dict block:^(NSString *string) { // use string here }]; 

Espero eso ayude. Puede consultar el ejemplo de iOS que AFNetworking tiene

Recomiendo encarecidamente usar esta oportunidad para convertir a la propia NSURLConnection Apple, en lugar de adoptar otra API de terceros. De esta forma, puede estar seguro de que no se suspenderá. He descubierto que el trabajo adicional requerido para que funcione es mínimo , pero resulta mucho más sólido y less propenso a errores.

Mi solución es manualmente ejecutar el thread runloop actual hasta que se haya procesado la callback.

Aquí está mi código.

 - (void)testRequest { MyHTTPClient* api = [MyHTTPClient shanetworkingInstance]; // subclass of AFHTTPClient NSDictionary* parameters = [NSDictionary dictionary]; // add query parameters to this dict. __block int status = 0; AFJSONRequestOperation* request = [api getPath:@"path/to/test" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) { // success code status = 1; NSLog(@"succeeded"); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { // failure status = 2; NSLog(@"failed"); }]; [api enqueueHTTPRequestOperation:request]; [api.operationQueue waitUntilAllOperationsAreFinished]; while (status == 0) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate date]]; } STAssertEquals(status, 1, @"success block was executed"); }