I have some misunderstanding in using NSURLSession
framework, that's why I decided to write small app from scratch without AFFramework/Alamofire.
I have an API that requires following steps to upload file:
- POST file data
- Get response (JSON)
- Post some json fields to
api/save
I have a background session with such config:
let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("myBackground")
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)
I've implemented 2 methods:
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData)
where I aggregate all data
and
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?)
where I tranform this data to response object. This response object if VERY important for me.
Everything works fine, while app is in foreground, but I have problems in background.
Case 1
App crashed right after I've started to upload data. According to WWDC I need to implement
func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: () -> Void)
and call this handler in didCompleteWithError
method. But before calling this method I need to call api/save
with data from upload response.
How can I get this data?
Case 2
Mostly similar case. User stops app while upload is in progress. Than loads app in few seconds, while session works with my task. Now session calls didReceiveData
, but of course, some of data is missing. What should I do in such case? How to restore response data?
You don't mention implementing
URLSessionDidFinishEventsForBackgroundURLSession
(aNSURLSessionDelegate
method). You really want to implement that, too. The basic process is:In app delegate's
handleEventsForBackgroundURLSession
, you should:NSURLSession
(which will start receiving delegate method calls associated with all of the uploads); andThen, in
URLSessionDidFinishEventsForBackgroundURLSession
(when you're done processing all of the responses), you call the completion handler you saved inhandleEventsForBackgroundURLSession
. (Make sure to dispatch that to the main queue.)If you're doing all of that, when the background session is restarted, the
didReceiveData
calls will come in with the responses to your various uploads.I just did a quick test, uploading five 20mb images and immediately terminating the app. Then, even though the app wasn't running, I watched the five files slowly show up on my server (obviously handled by the daemon process). When all five were done, by app was transparently restarted in the background, the
handleEventsForBackgroundURLSession
was called (which restarted the session), it let all of thedidReceiveData
calls quickly get called, and when that was done,URLSessionDidFinishEventsForBackgroundURLSession
was called and my app only then called the saved completion handler.In terms of why this isn't working for you, there's not enough to diagnose the problem. Possibilities include:
Maybe you terminated the app inappropriately. You can't kill the app by double tapping the home button and terminating the app there; you have to let it naturally terminate on it's own, or for diagnostic/testing purposes, I force it to terminate by calling
exit(0)
in code.Maybe you didn't restart the session when
handleEventsForBackgroundURLSession
was called.Maybe you called the supplied completion handler too soon (i.e. before
URLSessionDidFinishEventsForBackgroundURLSession
was called).It's hard to say, but I suspect that there's something buried inside your implementation that isn't quite right and it's hard to say what it is on the basis of the information provided (assuming it isn't one of the above points). Unfortunately, debugging this background sessions is vexingly complicated because when the app terminates, it is no longer attached to the debugger, so you can't easily debug what happens after the app is restarted automatically by iOS). Personally, I either
NSLog
messages and just watch the device console (as well as watching what appears on the server), or I build some persistent logging mechanism into the app itself.For testing Background session code it is recommended to test on a real device. When writing an app that uses NSURLSession’s background session support, it’s easy to get confused by three non-obvious artifacts of the development process:
Source: Apple Developer Forum