I have a problem when it comes to a slow backend and downloading data with background configuration.
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier];
_backgroundSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];
NSURLSessionDownloadTask *downloadTask = [_backgroundSession downloadTaskWithURL:URL];
[downloadTask resume];
If the connection is astablished but it takes more than 60 seconds for it to send back data a timeout occurs. That is fine. However the behaviour I experience is that I don't get an Error. The Session just sends out a new request. "Give me data again". I have no idea where this happens. Not in my code and no delegate methods are called that I'm aware of. I just have access to the server logs. It takes the server roughly 68 seconds to send back data but the app just ignores it because it's waiting for the new request.
One solution is to increase the timeout value. But I don't like it and it only works for iOS 7. Not iOS 8.
sessionConfig.timeoutIntervalForRequest = 10 * 60.0;
Does anyone have any insight in this? I found this link about timeout issue for background session here on stackoverflow. It's 10 months old but no solutions, only people agreeing.
I managed to solve it. I'm not saying my solution is the solution but it's a solution.
The behaviour I'm experiencing is that iOS 7 and iOS 8 prioritises properties differently. I have two places to set these timeout properties, the NSURLSessionConfiguration and in the NSMutableURLRequest. iOS 7 couldn't care less about the requests property and iOS 8 couldn't care less about the configurations property. Right now my solution looks like this:
NSURLSessionConfiguration *sessionConfig;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:identifier];
}
else {
sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier];
}
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0) {
sessionConfig.timeoutIntervalForRequest = 5 * 60.0;
}
_backgroundSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
request.timeoutInterval = 5 * 60.0;
}
NSURLSessionDownloadTask *downloadTask = [_backgroundSession downloadTaskWithRequest:request];
I guess one could just not do the systemVersion checks and set both properties to the same value. Although I strongly believe that less code is more I believe even more strongly in not affecting states that does not need to be affected. However I would love to hear peoples opinions. And if someone has a better solution please share.
Oh one more thing. The retrying part will keep happening until timeoutIntervalForResource reaches its default value of 7 days according to the documentation. I have decreased this to 10 minutes.
sessionConfig.timeoutIntervalForResource = 10 * 60;
I'm not saying it should be changed. This is a decision we made for our specific environment setup.
Update
We changed the timeoutIntervalForResource back to the default value of 7 days. We have customers in China for instance and some of them have really poor connection. A master limit of 10 minutes was just silly.
Make sure to check out Sunkas answer for better code quality. My code snippet, however, is spread out over different classes so I can't reuse that approach 100 %.