如何设置与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”。