I have recently migrated from ASIHTTPRequest to AFNetworking, which has been great. However, the server that I am connecting with has some issues and sometimes causes my requests to timeout. When using ASIHTTPRequest it was possible to setup a retry count on a request in the event of a timeout using the following selector
-setNumberOfTimesToRetryOnTimeout:
This can be further referenced in this post, Can an ASIHTTPRequest be retried?
This is AFNetworking if you are unfamiliar https://github.com/AFNetworking/AFNetworking#readme
I was unable to find an equivalent api in AFNetworking, has anyone found a solution for retrying network requests in the event of timeout using AFNetworking?
Matt Thompson developer of AFNetworking was kind enough to answer this for me. Below is the github link explaining the solution.
https://github.com/AFNetworking/AFNetworking/issues/393
Basically, AFNetworking doesn't support this functionality. It is left to the developer to implement on a case by case basis as shown below (taken from Matt Thompson's answer on github)
- (void)downloadFileRetryingNumberOfTimes:(NSUInteger)ntimes
success:(void (^)(id responseObject))success
failure:(void (^)(NSError *error))failure
{
if (ntimes <= 0) {
if (failure) {
NSError *error = ...;
failure(error);
}
} else {
[self getPath:@"/path/to/file" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (success) {
success(...);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[self downloadFileRetryingNumberOfTimes:ntimes - 1 success:success failure:failure];
}];
}
}
I implemented private method in my ApiClient class:
- (void)sendRequest:(NSURLRequest *)request successBlock:(void (^)(AFHTTPRequestOperation *operation, id responseObject))successBlock failureBlock:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failureBlock
{
__block NSUInteger numberOfRetries = 3;
__block __weak void (^weakSendRequestBlock)(void);
void (^sendRequestBlock)(void);
weakSendRequestBlock = sendRequestBlock = ^{
__strong typeof (weakSendRequestBlock)strongSendRequestBlock = weakSendRequestBlock;
numberOfRetries--;
AFHTTPRequestOperation *operation = [self.httpManager HTTPRequestOperationWithRequest:request success:successBlock failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSInteger statusCode = [[[error userInfo] objectForKey:AFNetworkingOperationFailingURLResponseErrorKey] statusCode];
if (numberOfRetries > 0 && (statusCode == 500 || statusCode == 502 || statusCode == 503 || statusCode == 0)) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
strongSendRequestBlock();
});
} else {
if (failureBlock) {
failureBlock(operation, error);
}
}
}];
[self.httpManager.operationQueue addOperation:operation];
};
sendRequestBlock();
}
Example of usage:
- (void)getSomeDetails:(DictionaryResultBlock)block
{
if (!block) {
return;
}
NSString *urlString = @"your url string";
NSMutableURLRequest *request = [self.httpManager.requestSerializer requestWithMethod:@"POST" URLString:[[NSURL URLWithString:urlString relativeToURL:self.defaultUrl] absoluteString] parameters:nil error:nil];
// Configure you request here
[request setValue:version forHTTPHeaderField:@"client-version"];
NSMutableDictionary *bodyParams = @{};
[request setHTTPBody:[NSJSONSerialization dataWithJSONObject:bodyParams options:0 error:nil]];
[self sendRequest:request successBlock:^(AFHTTPRequestOperation *operation, id responseObject) {
id response = [NSJSONSerialization JSONObjectWithData:responseObject options:0 error:nil];
block(response, nil);
} failureBlock:^(AFHTTPRequestOperation *operation, NSError *error) {
block(nil, error);
}];
}
In my case, I frequently required retry functionality so I came up wit this retry policy category that will help you with that AFNetworking+RetryPolicy
With respect to AFNetworking 3.0 it could serve well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With