NSURLSessionDownloadTask Continues Retrying When Using Background Configuration

I have a problem when it comes to slow backend and loading data with background setting.

NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier]; _backgroundSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil]; NSURLSessionDownloadTask *downloadTask = [_backgroundSession downloadTaskWithURL:URL]; [downloadTask resume]; 

If the connection is established, but it takes more than 60 seconds to send the data back, a timeout will occur. This is normal. However, the behavior that I am experiencing is that I am not receiving an error message. The session simply sends a new request. "Give me the data again." I have no idea where this is going. It is not in my code that the delegate methods that I know of are not called. I just have access to server logs. It takes the server about 68 seconds to send data, but the application simply ignores it because it is waiting for a new request.

One solution is to increase the timeout value. But I don’t like it, and it works only for iOS 7. Not iOS 8.

 sessionConfig.timeoutIntervalForRequest = 10 * 60.0; 

Does anyone have an insight into this? I found this timeout link for the background session here on stackoverflow. This is 10 months, but no decisions, only people agree.

+5
source share
3 answers

I managed to solve it. I am not saying that my decision is a decision , but it is a .

The behavior I am experiencing is that iOS 7 and iOS 8 prioritize properties in different ways. I have two places to set these timeout properties, NSURLSessionConfiguration and in NSMutableURLRequest . iOS 7 does not care about query properties, and iOS 8 cannot care about configuration properties. My solution now 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 think you can simply not do systemVersion checks and set both properties to the same value. Although I firmly believe that less code is more, I find it even stronger without affecting states that should not be affected. However, I would like to hear the opinions of people . And if anyone has a better solution, please share .

One more thing. The repeating part will continue until timeoutIntervalForResource reaches the default value of 7 days according to the documentation. I reduced it to 10 minutes.

 sessionConfig.timeoutIntervalForResource = 10 * 60; 

I am not saying that this should be changed. This is the decision we made for our particular environment setup.

Update

We changed timeoutIntervalForResource to the default value of 7 days. For example, we have customers in China, and some of them are really poorly connected. The 10 minute master limit was just stupid.

Be sure to check out Sunkas answer for better code quality. However, my code snippet extends to different classes, so I cannot reuse this approach 100%.

+3
source

I can’t stop, here is your answer a little reorganized :)

 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; NSURLSessionConfiguration *sessionConfig; float timeout = 5 * 60.0f; BOOL iOS8OrNewer = [[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0; if (iOS8OrNewer) { sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:identifier]; request.timeoutInterval = timeout; } else { sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier]; sessionConfig.timeoutIntervalForRequest = timeout; } _backgroundSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil]; NSURLSessionDownloadTask *downloadTask = [_backgroundSession downloadTaskWithRequest:request]; 
+6
source

Since iOS8, NSUrlSession in the background does not call this delegate method if the server is not responding. -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error Download / Download remains inactive. This delegate is called on iOS7 with an error when the server is not responding.

In general, an NSURLSession background session does not interrupt a task if something goes wrong on the wire. Rather, he continues to look for a suitable time to start the request and retry at that time. This continues until the resource has timed out (that is, the value of the timeoutIntervalForResource property in the NSURLSessionConfiguration object that you use to create the session). The current default value for this value is one week! In other words, the timeout error behavior in iOS7 was incorrect. In the context of a background session, immediate interruption due to network problems is more interesting. Since iOS8, the NSURLSession task continues even if it encounters timeouts and network loss. It continues, however, until the time interval IntervalForResource is reached.

So basically timeoutIntervalForRequest will not work in the background session, but timeoutIntervalForResource will.

Source: Apple Forum

+3
source

Source: https://habr.com/ru/post/1204722/


All Articles