A few thoughts:
First create a session using delegate , because background sessions must have a delegate:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:kSessionIdentifier]; self.session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
Second, create an instance of NSURLSessionUploadTask without a completion handler because tasks added to the background session cannot use completion blocks. Also note: I'm using the file url, not NSData :
NSURLSessionTask *task = [self.session uploadTaskWithRequest:request fromFile:fileURL]; [task resume];
Third, follow the appropriate delegate methods. At a minimum, it might look like this:
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { NSMutableData *responseData = self.responsesData[@(dataTask.taskIdentifier)]; if (!responseData) { responseData = [NSMutableData dataWithData:data]; self.responsesData[@(dataTask.taskIdentifier)] = responseData; } else { [responseData appendData:data]; } } - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { if (error) { NSLog(@"%@ failed: %@", task.originalRequest.URL, error); } NSMutableData *responseData = self.responsesData[@(task.taskIdentifier)]; if (responseData) {
Note that the above uses a previously created NSMutableDictionary called responsesData (because, to my chagrin, these delegation methods for the “task” are executed at the “session” level).
Finally, you want to define the storageHandler property provided by handleEventsForBackgroundURLSession :
@property (nonatomic, copy) void (^backgroundSessionCompletionHandler)(void);
And, obviously, respond to your application delegate with handleEventsForBackgroundURLSession , retaining the completionHandler , which will be used below in the URLSessionDidFinishEventsForBackgroundURLSession method.
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
And then make sure your NSURLSessionDelegate calls this handler in the main thread when the background session is running:
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { if (self.backgroundSessionCompletionHandler) { dispatch_async(dispatch_get_main_queue(), ^{ self.backgroundSessionCompletionHandler(); self.backgroundSessionCompletionHandler = nil; }); } }
This is only called if some of the downloads are completed in the background.
There are several moving parts, as you can see, but mostly this entails.