3

From the doc it looks like uploading a file is a good use case for using begin​Background​Task​With​Expiration​Handler​. I've found that using

let uploadTask = session.uploadTask(with: request as URLRequest, fromFile: file)
uploadTask.resume()

will already run while the app is backgrounded (I'm getting upload progress pings for a while). Additionally I can set the URLSession to be backgrounded:

let config = URLSessionConfiguration.background(withIdentifier: "uploads")
session = URLSession(configuration: config, delegate: self, delegateQueue: nil)

So what is the advantage of using begin​Background​Task​With​Expiration​Handler ? Will it extend the time I've to finish my upload? If so can I know by how much (didn't see anything about this in the doc)? Or is it just that I'll get pinged before the app stops? Should I use it in combination with a background URLSession?

Additionally the docs says that the handler will be called shortly before the app’s remaining background time reaches 0 Does it mean that the app will be terminated after that? ie can I assume that the next call will be application:didFinishLaunchingWithOptions or can it be applicationDidBecomeActive ?

Honey
  • 24,125
  • 14
  • 123
  • 212
Guig
  • 8,612
  • 5
  • 47
  • 99
  • 1
    Also, be aware that the background execution you see while running under Xcode is different to what you get with "normal" execution. Under Xcode you get unlimited background time. – Paulw11 Mar 31 '17 at 20:39
  • Ah great. @Paulw11 when you say "under Xcode" does it mean while running on my device from Xcode, or just in the simulator? I added info on background URLSession since I'm wondering if I should use that in combinaison with `begin​Background​Task​With​Expiration​Handler` or if a background URLSession is smart enough to handle all backgrounding events – Guig Mar 31 '17 at 20:43
  • 1
    Both under the simulator and on your device if you start the run from Xcode. If you run in the background for long enough you will see bakckgroundTimeRemaining reach 0 but your app continues. Normally your app will be killed at that point. – Paulw11 Mar 31 '17 at 20:48

2 Answers2

2

So what is the advantage of using begin​Background​Task​With​Expiration​Handler ?

If you are going to use URLSessionConfiguration.background, there is no such advantage and you should not use beginBackgroundTask(expirationHandler:) at all. Your entire premise (your very first sentence) was wrong. Uploading a file is not a good use case for beginBackgroundTask(expirationHandler:). It's a good use case for URLSessionConfiguration.background. The two things have nothing to do with each other.

matt
  • 447,615
  • 74
  • 748
  • 977
  • 1
    Ah! And the doc says "For example, your app could call this method to ensure that had enough time to transfer an important file to a remote server "... – Guig Mar 31 '17 at 20:49
  • @Guig if you are already in the middle of something (something _short_) and you are worried that the user might background your app and thus interrupt it, you can ask for a _brief_ extension of running time as we go into the background, just in order to complete that thing. An upload is unlikely to be a good fit (might not be short at all). That is _orthogonal_ to the notion of doing a `background` URL session; the latter enlists the system to do a long networking activity on your behalf at _any_ time it sees fit. – matt Apr 01 '17 at 13:35
2

This background task will let your app continue to run in background after the user leaves your app for an extra 3 minutes or so (check background​Time​Remaining for actual value) to let your request finish. And, yes, near the end of that 3 minutes, the timeout handler will be called if you haven't yet ended the background task.

So, if you end the background task during the normal flow of your app, this timeout closure won't need to be called. This closure is solely for any quick, last minute cleanup, that you might need to do before your app stops running in the background because it timed out before you had a chance to indicate that the background task ended. It's not for starting anything new, but just any last second clean-up. And make sure to end the background task in this timeout handler ... if you don't end the background task, the OS will summarily kill your app rather than just suspending it. Often, the only thing you need to do in this timeout closure is end the background task, but if you need to do any other cleanup, this is where you can do it.

Needless to say, you must end your background task (either when the network request finishes, or in the timeout handler if your app didn't yet get a chance to end the background task in its normal flow). If you don't, your app won't just be suspended, but rather it will be killed.

Regarding making assumptions about what happens when your app is restarted by the user later, you can't make any assumes about which app delegate method will be called. Even if you gracefully ended the background task, you have no assurances that it won't get jettisoned for other reasons (e.g. memory pressure). So don't assume anything.

Rob
  • 371,891
  • 67
  • 713
  • 902
  • Thanks. Do you have a take on @Matt's answer that suggests that using `URLSessionConfiguration.background` is better and totally replaces the need for `begin​Background​Task​With​Expiration​Handler` since it "makes it possible for transfers to continue even when the app itself is suspended or terminated." https://developer.apple.com/reference/foundation/urlsessionconfiguration/1407496-background – Guig Mar 31 '17 at 21:53
  • Background sessions are great for uploading/downloading many large assets or if the user might be offline when you send the request. But it's a lot more complicated than standard `URLSession` API, so you have to weigh the pros and cons. Some situations call for background `URLSession`. Sometimes this simple background task API is all you need. – Rob Mar 31 '17 at 21:58
  • 2
    FYI, if you are using background `URLSession`, then this background task stuff is completely unnecessary. You generally use one or the other. – Rob Mar 31 '17 at 22:04
  • I see. Can you say more on why it's _a lot_ more complicated? From what I've seen I have to handle `application:​handle​Events​For​Background​URLSession:​completion​Handler:​` and call the completion handler when done, but I didn't see anything more complicated in the doc and online examples. – Guig Mar 31 '17 at 22:05
  • 1
    You can't use data tasks, only upload and download tasks. Also, you can't use the convenient completion handler based API, but have to implement delegate based API. Also, if doing uploads, you can't do Data or Stream uploads, but only file-based uploads. You might check the performance as background requests can be a tad slower. Also, debugging is a little more complicated. None of this is rocket science, but it is more complicated than the simple default `URLSession` with completion handlers. – Rob Mar 31 '17 at 22:07
  • I see, so that's like using a URLSession with a delegate. I'll check performance since I also had the impression that is was quite slower. I guess I can start with `begin​Background​Task​With​Expiration​Handler` and if I don't have enough time, restart the upload in a backgrounded URLSession. – Guig Mar 31 '17 at 22:10