2

I have to download a long list of files and so all these operations may take a long time. I decided to manage these download tasks with a NSURLSession instantiated using a background configuration. Once built and ran the code onto my iPhone I try to test the application unplugging the device and launching the app without xCode. In that situation I notice that downloads no longer start if connection is not via WiFi. Moreover I notice that, during download operations, if the device goes into sleep mode, unlocking it after few seconds (10-15 seconds) app will be relaunched and downloads were stopped. I don't know if it is important but I hope that those issues not existed in iOS 8.2 (now I'm using iOS 8.3).

My session configuration is as follow

NSString *sessionIdentifier = @"com.yourappfor.example";
NSURLSessionConfiguration *sessionConfiguration;
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
    sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:sessionIdentifier];
} else {
    sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:sessionIdentifier];
}
[sessionConfiguration setAllowsCellularAccess:YES];
[sessionConfiguration setSessionSendsLaunchEvents:YES];
[sessionConfiguration setURLCache:nil];
[sessionConfiguration setDiscretionary:YES];
[sessionConfiguration setTimeoutIntervalForRequest:90.0];
[sessionConfiguration setTimeoutIntervalForResource:43200.0];
[sessionConfiguration setHTTPMaximumConnectionsPerHost:15];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];
  • And when you say "downloads stopped", do you mean that they've failed with an error, or that they just don't appear to be resuming in a timely manner? If you turn on power and connect to wifi, do they resume? – Rob Apr 13 '15 at 22:42
  • No, no error returned. I reconnect wifi and downloads will resume – Alessandro Capra Apr 13 '15 at 23:06
  • OK. Then the problem is likely the `discretionary` setting. See http://stackoverflow.com/a/25653066/1271826. – Rob Apr 14 '15 at 12:00
  • Ok, but this behavior is incredible.. So there is no way to start download when application is in background? – Alessandro Capra Apr 14 '15 at 21:27
  • Hi must download a lot of small files, it is normal that some of these files will start download when app is suspended – Alessandro Capra Apr 14 '15 at 21:29
  • Yes, I try set discretionary == NO e perform my test while device is connected to the external power.. But the behavior remain the same – Alessandro Capra Apr 14 '15 at 21:35

2 Answers2

1

As discussed elsewhere (e.g. see https://stackoverflow.com/a/25653066/1271826) when you use discretionary it may consider the wifi status before starting the requests. As the discretionary documentation says:

When transferring large amounts of data, you are encouraged to set the value of this property [i.e., discretionary] to YES. Doing so lets the system schedule those transfers at times that are more optimal for the device. For example, the system might delay transferring large files until the device is plugged in and connected to the network via Wi-Fi. The default value of this property is NO.

I have confirmed this empirically:

  • I turned off wifi, started a discretionary background session, plugged in my device, and left it overnight, and when I got up in the morning, my requests still had not been performed. Only when I turned on wifi did they proceed (and seemed to do so very quickly).

  • I repeated that exercise the following night, this time with discretionary turned off. This time, the requests were performed, though not immediately. They were finished roughly 10 minutes later (as an aside, they probably would have taken less than a minute or so if performed normally, so the cellular-only background connection was significantly slower).

Bottom line, discretionary will consider wifi status when performing requests, but with discretionary turned off, requests will be performed on background sessions without wifi, albeit not very quickly.


It should be noted, though, this only applies for tasks that you start while the app is in foreground. As the discretionary documentation goes on to say:

The session object applies the value of this [i.e., discretionary] property only to transfers that your app starts while it is in the foreground. For transfers started while your app is in the background, the system always starts transfers at its discretion—in other words, the system assumes this property is YES and ignores any value you specified.

Community
  • 1
  • 1
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Thank you @Rob. But if the task starts when application is in background the `discretionary ` property is ignored and iOS will consider it as YES, right? So, in your opinion, if I let discretionary to NO, the downloads will be performed "immediately" also with no WiFi connection and, when application enters in background, they will be performed only if WiFi is available and sometimes in the future? – Alessandro Capra Apr 17 '15 at 10:12
  • The app uses `discretionary` if the app was running in the background when you _start_ the connection (ie, initiated during background fetch or silent push notification). But if you have started it it from foreground with `discretionary` off, it honors `discretionary` even if app enters background (or eventually terminates due to memory pressure). – Rob Apr 17 '15 at 11:06
  • Sorry Rob, my english is not perfect. What I'm trying to say is that, if I have a long list of files to download and all these files are downloaded one after the other, what happens? In fact, first files starts their downloads when application is in foreground (`discretionary ` == NO) but the last ones start their operations while app is entered in background. – Alessandro Capra Apr 17 '15 at 11:17
  • If the app was in foreground when you create the session and create the download tasks, then they'll honor the discretionary status even if the app goes into background by the time that some of those requests actually start. – Rob Apr 17 '15 at 11:57
  • But my tasks are created as soon as the one before is completed. Instead it is very likely that they timed out... – Alessandro Capra Apr 17 '15 at 13:44
  • So when download tasks are created they will be created while app is already in background but the session that manage them was created while app was in foreground and with its `discretionary ` = NO – Alessandro Capra Apr 17 '15 at 13:47
  • If the next task is only created _after_ the prior one finishes, (a) that's awfully inefficient; and (b) you don't have control over the discretionary status. Can you refactor it to create all of the download tasks up front, before the app is suspended? – Rob Apr 17 '15 at 13:56
  • I could try to rethink it in that way. But I don't understand why it is inefficient to create a task when the prior one finished – Alessandro Capra Apr 17 '15 at 15:45
  • Because they're sequential, and you introduce network latency between each of the requests. The ability to perform requests concurrently results in significant performance improvement. On top of that general networking issue, background sessions introduce even more latency, exaggerating the effect.. – Rob Apr 17 '15 at 16:21
  • Thank you @rob I will try to rethink all the library I developed with this advice. I will let you know how it will work. Thank for all your advices – Alessandro Capra Apr 17 '15 at 16:25
0

The 10-15 second wait time could be from the device locking up and then Apple's Data Protection Capability taking control.

See https://stackoverflow.com/a/25789737/4875987

Community
  • 1
  • 1
  • Please do not only provide the link to the other answer. Please add at least a short summary (for example the solution to the OP's problem, if any) of that answer to your answer, because if the other answer would be deleted, then your answer would be become less helpful. – honk May 07 '15 at 17:14