如何设置与AFNetworking的超时

我的项目正在使用AFNetworking。

https://github.com/AFNetworking/AFNetworking

如何拨打暂停? 自动柜员机没有互联网连接的故障块是不会触发2分钟左右的感觉。 等待长…

更改超时间隔几乎肯定不是解决您所描述问题的最佳解决scheme。 相反,它看起来像你真正想要的是HTTP客户端处理networking变得无法访问,不是?

AFHTTPClient已经有一个内置的机制,让你知道当互联网连接丢失时, -setReachabilityStatusChangeBlock:

慢速networking上的请求可能需要很长时间。 最好是相信iOS知道如何处理缓慢的连接,并告诉它们之间的区别,而根本就没有连接。


为了扩大我的理由,为什么应该避免在这个线程中提到的其他方法,这里有一些想法:

  • 请求可以在开始之前取消。 排队请求并不能保证它何时开始。
  • 超时间隔不应取消长时间运行的请求,特别是POST。 想象一下,如果你想下载或上传一个100MB的video。 如果这个请求在最慢的3Gnetworking上可以实现的话,那么为什么如果需要的时间比预期的要长一些,你会不必要地停下来呢?
  • 执行select器performSelector:afterDelay:...在multithreading应用程序中可能是危险的。 这使自己开始模糊和难以debugging的竞争条件。

我强烈build议看一下上面的mattt的答案 – 尽pipe这个答案并不违背他提到的问题,对于原来的海报问题,检查可达性是一个更好的select。

然而,如果你仍然想要设置一个超时(没有执行select器performSelector:afterDelay:等固有的问题,那么请求乐高提到了一个方法来做到这一点,作为其中一个注释,你只是这样做:

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

但看到警告@Kchaarwood提到,看来苹果公司不允许这改变POST请求(这是固定的iOS 6及以上)。

正如@ChrisopherPickslay所指出的那样,这不是一个总体超时,而是接收(或发送数据)之间的超时。 我不知道有什么办法明智地做一个整体超时。 苹果文档setTimeoutInterval说:

超时间隔,以秒为单位。 如果在连接尝试期间请求保持空闲的时间超过了超时间隔,则认为该请求超时。 默认超时间隔是60秒。

您可以通过requestSerializer setTimeoutInterval方法设置超时间隔。您可以从AFHTTPRequestOperationManager实例获取requestSerializer。

例如要做一个超时时间为25秒的发布请求:

  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 }]; 

我认为你现在必须手动补丁。

我是inheritanceAFHTTPClient并改变了

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

方法join

 [request setTimeoutInterval:10.0]; 

AFHTTPClient.m第236行。当然,如果可以configuration,这将是很好的,但据我所知,目前是不可能的。

最后找出了如何用asynchronousPOST请求来做到这一点:

 - (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]; } 

我testing了这个代码让我的服务器sleep(aFewSeconds)

如果你需要做一个同步POST请求, 不要使用[queue waitUntilAllOperationsAreFinished]; 。 而是使用与asynchronous请求相同的方法,并等待在selector参数中传递的函数被触发。

根据他人的回答和@ mattt对相关项目问题的build议,如果你是AFHTTPClient的子类,这里是一个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 

经testing可以在iOS 6上运行。

我们不能用这样的计时器来做到这一点:

在.h文件中

 { NSInteger time; AFJSONRequestOperation *operation; } 

在.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; } 

这里的“超时”定义有两个不同的含义。

timeoutInterval

您希望在空闲(不再传输)时间长于任意时间间隔的情况下删除请求。 例如:你设置timeoutInterval为10秒,你在12:00:00开始你的请求,它可能会传输一些数据直到12:00:23,然后连接将在12:00:33超时。 这个案子几乎涵盖了所有的答案(包括JosephH,Mostafa Abdellateef,Cornelius和Gurpartap Singh)。

timeoutDeadline

您希望在稍后发生任何截止date时放弃请求。 例如:您将deadline设置为10秒后,您在12:00:00开始请求,它可能会尝试传输一些数据至12:00:23,但连接将在12:00:10提前超时。 这个案子由borisdiakur覆盖。

我想展示如何在Swift(3和4)中实现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() } 

并给出一个可testing的例子,这个代码应该打印“失败”,而不是“成功”,因为在未来的0.0秒立即超时:

 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() } 

同意马特,你不应该尝试改变timeoutInterval。 但是,你也不应该依赖可达性检查来决定你要build立连接的天气,直到你尝试才会知道。

正如苹果文件所述:

一般来说,你不应该使用短的超时间隔,而应该为用户提供一个简单的方法来取消一个长时间运行的操作。 有关更多信息,请阅读“为真实世界networkingdevise”。