I'm working on an iOS app, uploading videos from the Camera Roll, using NSURLSession with a background configuration. The user can queue up multiple videos for upload (the queue is executed serially).
A single upload consists of:
requestAVAssetForVideo
method. I can queue up multiple videos and the process works well in the foreground. They complete one after another.
But if I queue up several videos and then background the app. As soon as execution reaches the exportAsynchronouslyWithCompletionHandler:
stage it stalls until I foreground the app again. (I know this because I'm posting debug statements in local notifications, visible on the lock screen).
Is it possible to use exportAsynchronouslyWithCompletionHandler:
when the app is backgrounded?
Edit 1 I've tested this while connected to the debugger and while not, the app never executes the copy command. But does so only when the app is foregrounded again.
Edit 2
I posted a similar question about whether using NSFileManager's copyItemAtURL:toURL:error:
is a viable alternative (but I'm seeing the same behavior so don't think it is).
In general, if you need just a little time (up to a few minutes) to finish up some tasks even after the user leaves the app, you just request this from the OS. See the Executing Finite Length Tasks section in the Background Execution Chapter. So, begin the background task when you call exportAsynchronouslyWithCompletionHandler
, and end it in the completion handler for that method.
If you are also using a background NSURLSession
. In that case, if the app is not in foreground when the tasks finish, it calls the app delegate's handleEventsForBackgroundURLSession
method, which passes a completionHandler
block. One must:
Save the completionHandler
provided to handleEventsForBackgroundURLSession
;
Instantiate the NSURLSession
with the same background identifier as the original background session;
Let the session call the appropriate delegate methods for the completion of the tasks; and
The session will call URLSessionDidFinishEventsForBackgroundURLSession
when they're all done, at which point you'd generally call the completionHandler
we originally received in the app delegate.
In your case, you will want to defer the call to the saved completionHandler
until after all of the asynchronous exportAsynchronouslyWithCompletionHandler
handlers are done, too. There are bunch of ways you could do that (e.g. dispatch groups, etc.), but hopefully that illustrates the moving parts involved in this process.