Good day,
I have a use case that I am currently facing problems with.
I am currently implementing a downloader service that uses some c++ code to download in the foreground, and when the user backgrounds the app, NSURLSession
kicks in.
Due to chunking, we have a bunch of endpoints that contain ~1mb worth of data for each chunk, and these chunks make up a full file when processed. Small files would be downloaded as is.
As such, there might potentially be ten thousands worth of endpoints that NSURLSession might need to download from in the background.
From what I've read around here, there are four things to take note of.
- Resume Rate Limiter
- Number of tasks queued into
nsurlsessiond
- Number of concurrently running tasks
NSUrlSessionDownloadTask
creation
My current implementation is to create a bunch of tasks in applicationDidEnterBackground(_:)
and then starting them all at once. However, NSUrlSessionDownloadTask
creation is very expensive. As a reference, it takes 3.7 seconds to create 400 tasks on my iPhone 7+.
Upwards of 500 task creation and it runs into the territory of the OS terminating my app as I did not return out of applicationDidEnterBackground(_:)
in five seconds.
Creation of new tasks when the first batch ends is also not an option because of resume rate limiter. According to here, the delay is really heavy and is something I would like to avoid.
Are there any viable solutions that would solve my problem of downloading many files in the background? Thanks in advance!
We can place a cap on the number of files that are able to be downloaded in the background, but what would be a good number?
One? (-:
Seriously though, your best option is a single, large, resumable download. Everything else just takes you away from that optimum.
As to how many you can get away with, that’s hard to say. Thousands is definitely bad and tens is definitely fine, so the cut off point is somewhere in the low hundreds.
If we were to do this, are we supposed to create a
NSURLSession
with a background configuration right off the bat, and use that for both foreground downloads and background downloads?
Why are you’re using libcurl
? My guess is that it’s adding a bunch of complexity without yielding much benefit.
As to how you manage your instances, my general advice is that you try to divide your network requests into groups based on their expected size and latency:
-
For small, interactive requests, run them in a standard session. These typically fail if your app gets suspended, but that’s not a problem because you can retry them when your app resumes.
-
For large requests, run them in a background session. These will continue if your app gets suspend.
Or is there a way that we can still use curl in the foreground, and then startup a
NSURLSessionDownload
to be used in the background and resume the rest of the downloads there?
I don’t really understand your question, so let’s start with some factoids:
-
libcurl
has no special affordance in iOS, so it’ll only work if your app remains running. -
By default the system suspends your app shortly after moving it to the background.
-
When that happens, your
libcurl
code will stop execution and an in-flight transfers will fail. -
There’s no specific mechanism to take a partial download done by
libcurl
and create aNSURLSessionDownloadTask
to continue the download in a background session. -
However, if your server supports byte ranges you could probably make that work.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"