我的项目正在使用AFNetworking。
https://github.com/AFNetworking/AFNetworking
如何降低超时时间?没有互联网连接的自动取款机大约2分钟之内不会触发故障阻止。漫长的...
我的项目正在使用AFNetworking。
https://github.com/AFNetworking/AFNetworking
如何降低超时时间?没有互联网连接的自动取款机大约2分钟之内不会触发故障阻止。漫长的...
Answers:
更改超时间隔几乎绝对不是解决您所描述问题的最佳解决方案。相反,似乎您真正想要的是让HTTP客户端处理无法访问的网络,不是吗?
AFHTTPClient
已经具有内置机制,可以在互联网连接断开时通知您-setReachabilityStatusChangeBlock:
。
在慢速的网络上,请求可能会花费很长时间。最好让iOS知道如何处理慢速连接,并告诉它与根本没有连接之间的区别。
为了进一步说明为什么应避免使用此线程中提到的其他方法的原因,这里有一些想法:
performSelector:afterDelay:...
在多线程应用程序中这样做可能很危险。这为模糊和难以调试的比赛条件敞开了自己的大门。我强烈建议您查看上面的mattt答案-尽管此答案不会与他通常提到的问题相抵触,但对于原始发帖人问题,检查可达性更合适。
但是,如果您仍然想设置一个超时时间(而没有performSelector:afterDelay:
etc中固有的所有问题,那么Lego的pull request提述方法将其描述为一种注释方式),您可以这样做:
NSMutableURLRequest *request = [client requestWithMethod:@"GET" path:@"/" parameters:nil];
[request setTimeoutInterval:120];
AFHTTPRequestOperation *operation = [client HTTPRequestOperationWithRequest:request success:^{...} failure:^{...}];
[client enqueueHTTPRequestOperation:operation];
但请注意,@ KCHarwood需要注意的是,Apple似乎不允许对POST请求进行更改(在iOS 6及更高版本中已修复)。
正如@ChrisopherPickslay指出的那样,这不是整体超时,而是在接收(或发送数据)之间的超时。我不知道有任何方法可以合理地进行整体超时。Apple关于setTimeoutInterval的文档说:
超时时间间隔,以秒为单位。如果在连接尝试期间请求保持空闲状态超过超时间隔,则认为该请求已超时。默认超时间隔为60秒。
timeoutInterval
是一个空闲计时器,不是请求超时。因此,您必须在120秒内完全不接收任何数据,以上代码才能超时。如果数据缓慢滴入,则请求可能会无限期地继续。
您可以通过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
}];
我认为您现在必须手动对此进行修补。
我将AFHTTPClient子类化,并更改了
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters
通过添加方法
[request setTimeoutInterval:10.0];
在AFHTTPClient.m第236行中。如果可以进行配置,那当然会很好,但是据我所知,目前尚无法实现。
最终发现了如何使用异步POST请求来执行此操作:
- (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)
。
如果您需要执行同步POST请求,请不要使用[queue waitUntilAllOperationsAreFinished];
。而是使用与异步请求相同的方法,并等待触发在选择器参数中传递的函数。
根据其他人的答案和@mattt对相关项目问题的建议,如果您要进行子类化,则可以使用以下便捷工具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
经测试可在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
您希望在一个截止日期之后任意发生的情况下删除该请求。例如:您设置deadline
为将来的10秒,您在12:00:00发起请求,它可能会尝试传输一些数据,直到12:00:23,但连接将在12:00:10之前超时。此案由borisdiakur负责。
我想展示如何在AFNetworking 3.1的Swift(第3和第4版)中实现此截止日期。
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()
}
并给出一个可测试的示例,此代码应打印“ failure”(失败)而不是“ success”(成功),因为将来立即超时为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()
}
performSelector:afterDelay:...
用于手动取消现有操作的解决方案。请参阅我的答案以获取更多详细信息。