last example afhttprequestoperation objective-c ios xcode networking afnetworking

objective-c - example - alamofire last version



Cómo establecer un tiempo de espera con AFNetworking (9)

Mi proyecto está usando AFNetworking.

https://github.com/AFNetworking/AFNetworking

¿Cómo marque el tiempo de espera? Causa sin conexión a Internet. El bloqueo fallido no se activa durante aproximadamente 2 minutos. Waay a largo ....


¿No podemos hacer esto con un temporizador como este?

En archivo .h

{ NSInteger time; AFJSONRequestOperation *operation; }

En archivo .m

-(void)AFNetworkingmethod{ time = 0; NSTtimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(startTimer:) userInfo:nil repeats:YES]; [timer fire]; operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) { [self operationDidFinishLoading:JSON]; } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) { [self operationDidFailWithError:error]; }]; [operation setJSONReadingOptions:NSJSONReadingMutableContainers]; [operation start]; } -(void)startTimer:(NSTimer *)someTimer{ if (time == 15&&![operation isFinished]) { time = 0; [operation invalidate]; [operation cancel]; NSLog(@"Timeout"); return; } ++time; }


Aquí hay dos significados diferentes en la definición de "tiempo de espera".

Tiempo de espera como en timeoutInterval

Desea soltar una solicitud cuando esté inactiva (no más transferencia) durante más tiempo que un intervalo arbitrario de tiempo. Ejemplo: establece timeoutInterval en 10 segundos, inicia su solicitud a las 12:00:00, puede transferir algunos datos hasta las 12:00:23, luego la conexión expirará a las 12:00:33. Este caso está cubierto por casi todas las respuestas aquí (incluidos Joseph H., Mostafa Abdellateef, Cornelius y Gurpartap Singh).

Tiempo de espera como en timeoutDeadline

Desea soltar una solicitud cuando llega a un plazo arbitrario más tarde. Ejemplo: establece una deadline de 10 segundos en el futuro, inicia su solicitud a las 12:00:00, puede intentar transferir algunos datos hasta las 12:00:23, pero la conexión expirará antes a las 12:00:10. Este caso está cubierto por borisdiakur.

Me gustaría mostrar cómo implementar este plazo en Swift (3 y 4) para AFNetworking 3.1.

let sessionManager = AFHTTPSessionManager(baseURL: baseURL) let request = sessionManager.post(endPoint, parameters: parameters, progress: { ... }, success: { ... }, failure: { ... }) // timeout deadline at 10 seconds in the future DispatchQueue.global().asyncAfter(deadline: .now() + 10.0) { request?.cancel() }

Y para dar un ejemplo comprobable, este código debería imprimir "error" en lugar de "éxito" debido al tiempo de espera inmediato en 0.0 segundos en el futuro:

let sessionManager = AFHTTPSessionManager(baseURL: URL(string: "https://example.com")) sessionManager.responseSerializer = AFHTTPResponseSerializer() let request = sessionManager.get("/", parameters: nil, progress: nil, success: { _ in print("success") }, failure: { _ in print("failure") }) // timeout deadline at 0 seconds in the future DispatchQueue.global().asyncAfter(deadline: .now() + 0.0) { request?.cancel() }


Cambiar el intervalo de tiempo de espera es casi seguro que no es la mejor solución al problema que está describiendo. En cambio, parece que lo que realmente quiere es que el cliente HTTP maneje la red que se vuelve inalcanzable, ¿no?

AFHTTPClient ya tiene un mecanismo incorporado que le permite saber cuándo se pierde la conexión a Internet, -setReachabilityStatusChangeBlock:

Las solicitudes pueden tardar mucho tiempo en redes lentas. Es mejor confiar en iOS para saber cómo manejar las conexiones lentas y diferenciar entre eso y no tener ninguna conexión.

Para ampliar mi razonamiento sobre por qué se deben evitar otros enfoques mencionados en este hilo, aquí hay algunos pensamientos:

  • Las solicitudes pueden cancelarse incluso antes de que comiencen. Enrutar una solicitud no garantiza cuándo comienza realmente.
  • Los intervalos de tiempo de espera no deben cancelar las solicitudes de larga ejecución, especialmente POST. Imagínese si estuviera tratando de descargar o cargar un video de 100MB. Si la solicitud avanza lo mejor posible en una red 3G lenta, ¿por qué debería detenerla innecesariamente si tarda un poco más de lo esperado?
  • Hacer performSelector:afterDelay:... puede ser peligroso en aplicaciones de subprocesos múltiples. Esto se abre a condiciones de carrera oscuras y difíciles de depurar.

Con base en las respuestas de los demás y la sugerencia de @ mattt sobre problemas relacionados con el proyecto, aquí hay un rápido AFHTTPClient si está subclasificando AFHTTPClient :

@implementation SomeAPIClient // subclass of AFHTTPClient // ... - (NSMutableURLRequest *)requestWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters { NSMutableURLRequest *request = [super requestWithMethod:method path:path parameters:parameters]; [request setTimeoutInterval:120]; return request; } - (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block { NSMutableURLRequest *request = [super requestWithMethod:method path:path parameters:parameters]; [request setTimeoutInterval:120]; return request; } @end

Probado para trabajar en iOS 6.


Creo que tienes que parchear eso manualmente en este momento.

Estoy subclasificando AFHTTPClient y cambié el

- (NSMutableURLRequest *)requestWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters

método al agregar

[request setTimeoutInterval:10.0];

en AFHTTPClient.m línea 236. Por supuesto sería bueno si eso pudiera configurarse, pero hasta donde veo eso no es posible en este momento.


De acuerdo con Matt, no intentes cambiar el timeoutInterval. Pero tampoco debes confiar en la verificación de accesibilidad para decidir el tiempo en que harás la conexión, no lo sabes hasta que lo intentes.

Según lo declarado por el documento de Apple:

Como regla general, no debe usar intervalos cortos de tiempo de espera, y en su lugar, debe proporcionar una manera fácil para que el usuario cancele una operación de larga ejecución. Para obtener más información, lea "Diseño para redes reales".


Puede establecer el intervalo de tiempo de espera a través del método requestSerializer setTimeoutInterval. Puede obtener requestSerializer desde una instancia de AFHTTPRequestOperationManager.

Por ejemplo, para hacer una solicitud posterior con un tiempo de espera de 25 segundos:

NSDictionary *params = @{@"par1": @"value1", @"par2": @"value2"}; AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; [manager.requestSerializer setTimeoutInterval:25]; //Time out after 25 seconds [manager POST:@"URL" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) { //Success call back bock NSLog(@"Request completed with response: %@", responseObject); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { //Failure callback block. This block may be called due to time out or any other failure reason }];


Recomiendo mirar la respuesta de Mattt arriba, aunque esta respuesta no cae en los problemas que menciona en general, para la pregunta de los carteles originales, verificar la accesibilidad es mucho mejor.

Sin embargo, si aún desea establecer un tiempo de espera (sin todos los problemas inherentes en performSelector:afterDelay: etc, la solicitud de extracción que menciona Lego describe una manera de hacer esto como uno de los comentarios, solo lo hace:

NSMutableURLRequest *request = [client requestWithMethod:@"GET" path:@"/" parameters:nil]; [request setTimeoutInterval:120]; AFHTTPRequestOperation *operation = [client HTTPRequestOperationWithRequest:request success:^{...} failure:^{...}]; [client enqueueHTTPRequestOperation:operation];

pero vea la advertencia @KCHarwood menciona que parece que Apple no permite que esto se modifique para solicitudes POST (que se corrige en iOS 6 y versiones posteriores).

Como señala @ChrisopherPickslay, este no es un tiempo de espera total, es un tiempo de espera entre la recepción (o el envío de datos). No estoy al tanto de ninguna forma de hacer un tiempo de espera total. La documentación de Apple para setTimeoutInterval dice:

El intervalo de tiempo de espera, en segundos. Si durante un intento de conexión la solicitud permanece inactiva durante más tiempo que el intervalo de tiempo de espera, se considera que la solicitud ha expirado. El intervalo de tiempo de espera predeterminado es de 60 segundos.


Finalmente descubrió cómo hacerlo con una solicitud POST asíncrona:

- (void)timeout:(NSDictionary*)dict { NDLog(@"timeout"); AFHTTPRequestOperation *operation = [dict objectForKey:@"operation"]; if (operation) { [operation cancel]; } [[AFNetworkActivityIndicatorManager sharedManager] decrementActivityCount]; [self perform:[[dict objectForKey:@"selector"] pointerValue] on:[dict objectForKey:@"object"] with:nil]; } - (void)perform:(SEL)selector on:(id)target with:(id)object { if (target && [target respondsToSelector:selector]) { [target performSelector:selector withObject:object]; } } - (void)doStuffAndNotifyObject:(id)object withSelector:(SEL)selector { // AFHTTPRequestOperation asynchronous with selector NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys: @"doStuff", @"task", nil]; AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:baseURL]]; NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" path:requestURL parameters:params]; [httpClient release]; AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease]; NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys: operation, @"operation", object, @"object", [NSValue valueWithPointer:selector], @"selector", nil]; [self performSelector:@selector(timeout:) withObject:dict afterDelay:timeout]; [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(timeout:) object:dict]; [[AFNetworkActivityIndicatorManager sharedManager] decrementActivityCount]; [self perform:selector on:object with:[operation responseString]]; } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NDLog(@"fail! /nerror: %@", [error localizedDescription]); [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(timeout:) object:dict]; [[AFNetworkActivityIndicatorManager sharedManager] decrementActivityCount]; [self perform:selector on:object with:nil]; }]; NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease]; [[AFNetworkActivityIndicatorManager sharedManager] incrementActivityCount]; [queue addOperation:operation]; }

sleep(aFewSeconds) este código dejando que mi servidor sleep(aFewSeconds) .

Si necesita hacer una solicitud POST síncrona, NO use [queue waitUntilAllOperationsAreFinished]; . En su lugar, use el mismo enfoque que para la solicitud asincrónica y espere a que se active la función que usted transfiere en el argumento del selector.