NSURLSessionDownloadTask keeps retrying when using Background Configuration

后端 未结 4 1569
礼貌的吻别
礼貌的吻别 2021-02-04 17:08

I have a problem when it comes to a slow backend and downloading data with background configuration.

NSURLSessionConfiguration *sessionConfig = [NSURLSessionConf         


        
相关标签:
4条回答
  • 2021-02-04 17:34

    Could not stop myself, here is your answer a bit refactored :)

    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];
    
    0 讨论(0)
  • 2021-02-04 17:37

    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 %.

    0 讨论(0)
  • 2021-02-04 17:51

    Another Apple discussion that relates to the retry loops that occur when server responses to background upload tasks take too long:

    https://forums.developer.apple.com/thread/70682

    0 讨论(0)
  • 2021-02-04 17:53

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

    In general, an NSURLSession background session does not fail a task if something goes wrong on the wire. Rather, it continues looking for a good time to run the request and retries at that time. This continues until the resource timeout expires (that is, the value of the timeoutIntervalForResource property in the NSURLSessionConfiguration object you use to create the session). The current default for that value is one week! In other words, the behaviour of failing for a timeout in iOS7 was incorrect. In the context of a background session, it is more interesting to not fail immediately because of network problems. So since iOS8, NSURLSession task continues even if it encounters timeouts and network loss. It continues however until timeoutIntervalForResource is reached.

    So basically timeoutIntervalForRequest won't work in Background session but timeoutIntervalForResource will.

    Source: Apple Forum

    0 讨论(0)
提交回复
热议问题