2012-05-20 10 views
7

Realizo una solicitud JSON con AFNetworking y luego llamo a [operation waitUntilFinished] para esperar la operación y los bloques de éxito o falla. Sin embargo, parece caer directo, aunque - en cuanto a los mensajes de registro, recibo "0", "3", "1" en lugar de "0", "1", "3"Esperando completar el bloque de finalización en una solicitud de AFNetworking

NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://google.com"]]; 
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url]; 
httpClient.parameterEncoding = AFFormURLParameterEncoding; 
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:@"query", @"q", nil]; 
NSMutableURLRequest *request = [httpClient requestWithMethod:@"GET" path:[url path] parameters:params]; 
NSLog(@"0"); 
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *innerRequest, NSHTTPURLResponse *response, id JSON) { 
NSLog(@"1"); 
gotResponse = YES; 
} failure:^(NSURLRequest *innerRequest, NSHTTPURLResponse *response, NSError *error, id JSON) { 
    NSLog(@"2"); 
    gotResponse = YES; 
}]; 
NSLog(@"Starting request"); 
[operation start]; 
[operation waitUntilFinished]; 
NSLog(@"3"); 
+0

Parece que la llamada a '[operation waitUntilFinished]' no espera en los bloques de finalización. AFJSONRequestOperation.m los ejecuta con 'dispatch_async', que creo que se convierte en parte de una operación separada. ¿Es correcto y hay una forma de evitarlo? – Kamran

Respuesta

14

Esto funciona usando AFNetworking para configurar las solicitudes, pero haciendo una llamada síncrona y luego manejando los bloques de finalización manualmente. Muy simple. AFNetworking no parece ser compatible con este https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-FAQ, aunque el trabajo es lo suficientemente simple.

#import "SimpleClient.h" 

#import "AFHTTPClient.h" 
#import "AFJSONRequestOperation.h" 
#import "AFJSONUtilities.h" 

@implementation SimpleClient 

+ (void) makeRequestTo:(NSString *) urlStr 
     parameters:(NSDictionary *) params 
     successCallback:(void (^)(id jsonResponse)) successCallback 
     errorCallback:(void (^)(NSError * error, NSString *errorMsg)) errorCallback { 

    NSURLResponse *response = nil; 
    NSError *error = nil; 

    NSURL *url = [NSURL URLWithString:urlStr]; 

    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url]; 

    httpClient.parameterEncoding = AFFormURLParameterEncoding; 

    NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" path:[url path] parameters:params]; 
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; 

    if(error) { 
     errorCallback(error, nil); 
    } else { 
     id JSON = AFJSONDecode(data, &error); 
     successCallback(JSON); 
    } 
} 

@end 
0

Eso debería (casi) funcionar. Su llamada a

NSMutableURLRequest *request = [httpClient requestWithMethod:@"GET" path:[url path] parameters:params]; 

probablemente no debería pasar [url path] al parámetro path:. En el terreno de AFNetworking, ese camino lo es todo después de la url base (por ejemplo, la URL base podría ser "http://google.com" y la ruta "/ gmail" o lo que sea).

Dicho esto, no es probablemente una buena idea para hacer la operación asincrónica en una operación síncrona hilo de bloqueo con waitUntilFinished, pero estoy seguro de que tiene sus razones ...;)

+0

Cambiado a la ruta: @ "/", pero el resultado es el mismo. – Kamran

0

Acabo de tener el mismo problema y he encontrado una solución diferente. Tuve dos operaciones que dependen unas de otras, pero pueden cargarse en paralelo. Sin embargo, el bloque de finalización de la segunda operación no puede ejecutarse antes de que el bloque de finalización de la segunda haya finalizado.

Como señaló Colin, podría ser una mala elección crear un bloque de solicitud web. Esto fue esencial para mí, así que lo hice de forma asíncrona.

Esta es mi solución:

// This is our lock 
@interface SomeController() { 
    NSLock *_dataLock; 
} 
@end 

@implementation 

// This is just an example, you might as well trigger both operations in separate 
// places if you get the locking right 
// This might be called e.g. in awakeFromNib 
- (void)someStartpoint { 
    AFJSONRequestOperation *operation1 = [AFJSONRequestOperation JSONRequestOperationWithRequest:[NSURLRequest requestWithURL:url1] 
                         success:^(NSURLRequest *request, NSHTTPURLResponse *response, id data) { 
     // We're done, we unlock so the next operation can continue its 
     // completion block 
     [_dataLock unlock]; 
    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id data) { 
     // The request has failed, so we need to unlock for the next try 
     [_dataLock unlock]; 
    }]; 

    AFJSONRequestOperation *operation2 = [AFJSONRequestOperation JSONRequestOperationWithRequest:[NSURLRequest requestWithURL:url2] 
                         success:^(NSURLRequest *request, NSHTTPURLResponse *response, id data) { 
     // The completion block (or at least the blocking part must be run in a 
     // separate thread 
     [NSThread detachNewThreadSelector:@selector(completionBlockOfOperation2:) toTarget:self withObject:data]; 
    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id data) { 
     // This second operation may fail without affecting the lock 
    }]; 

    // We need to lock before both operations are started 
    [_dataLock lock]; 

    // Order does not really matter here 
    [operation2 start]; 
    [operation1 start]; 
} 

- (void)completionBlockOfOperation2:(id)data { 
    // We wait for the first operation to finish its completion block 
    [_dataLock lock]; 

    // It's done, so we can continue 

    // We need to unlock afterwards, so a next call to one of the operations 
    // wouldn't deadlock 
    [_dataLock unlock]; 
} 

@end 
+0

¿Por qué utilizar una solicitud asíncrona y luego forzarla a bloquear? Esto es propenso a errores, ya que si puede regresar de la devolución de llamada antes de llegar a la declaración de desbloqueo. – Kamran

+0

No es la solicitud lo que bloquea. Es la función lambda que se llama una vez que la solicitud ha finalizado. Esto asegura que la respuesta de la segunda solicitud (dependiente) no se evalúa hasta que la primera finalice. Las solicitudes en sí mismas se hacen en paralelo. – Koraktor

0

Uso Delegado método llamado

Ponga el método dentro del bloque que se llame a sí mismo cuando carga/descarga completa.

Cuestiones relacionadas