I'm trying to upload a series of files from iPhone up to a server, with the intent that the upload of these files happen even when the App is in the background or suspended.

I'm using **background transfer** provided by `NSURLSession` and its series of APIs.

**what was odd was it it was fully working 2 weeks ago**. As in: 

1. I would click the "upload" button on the UI
2. files would start to appear one by one on my server
3. I tap the "Home" button on the iPhone to make the app go into the background
4. Files would continue to upload to the server until it all completes

Last couple of days, I've been doing some refactoring outside of the network module. When I tried the upload again a couple of days ago, as soon as I hit "Home" button, step (3) above. File upload would stop, when I go into the app again. Upload would resume.

*It's as if background upload isn't even working (for one file, let alone multiple files).*

I've ran the code multiple times, and found about 1 / 50 times it works. But the other 49 times it doesn't. I've also checked out the version of the code that used to work (both server + iOS), and it no longer works - or rather, works vary rarely (the 1/50)

Having gone through the [rules](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/Articles/UsingNSURLSession.html) for Background transfer and [Lifecycle of URL Session](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/NSURLSessionConcepts/NSURLSessionConcepts.html) multiple times to make sure I'm adhering by Apple suggested guidelines, I'm racking my brain as to what broke, it boggles the mind how illogical this is - **I suspect it's something other than code implementation.**

So any help is appreciated...

Implementation
--------------

1) In `init` method for my network class (a singleton), I initialise the `NSURLSessionConfiguration` and `NSURLSession`:

```
    urlSessionConfigUpload = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:kBACKGROUND_SESSION_CONFIG_ID];
    urlSessionConfigUpload.sessionSendsLaunchEvents = YES;
    urlSessionConfigUpload.discretionary = YES;
    urlSessionConfigUpload.HTTPMaximumConnectionsPerHost = 8;
    urlSessionConfigUpload.networkServiceType = NSURLNetworkServiceTypeBackground;
    urlSessionConfigUpload.HTTPShouldUsePipelining = NO; 
    urlSessionConfigUpload.allowsCellularAccess = NO;

    urlSession = [NSURLSession sessionWithConfiguration:urlSessionConfigUpload delegate:self delegateQueue:nil];

```

2) There's a convenience method called to do the actual upload. There is only ever 1 upload task per session:

```
    NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
    [urlRequest setHTTPMethod:@"PUT"];
    [urlRequest addValue:@"keep-alive" forHTTPHeaderField:@"Connection"];
    [urlRequest addValue:contentType forHTTPHeaderField:@"Content-Type"];

    // NB: for upload task in the background, uploadTaskWithRequest:fromData (explicit construction of HTTP POST body) can’t be used,
    // must use uploadTaskWithRequest:fromFile (requiring HTTP PUT)
    NSURLSessionDataTask *uploadTask = [urlSession uploadTaskWithRequest:urlRequest fromFile:[NSURL fileURLWithPath:filePath]];
    [uploadTask resume];

```

3) In the `didCompleteWithError` delegate, I check if all files have been uploaded, if not, move onto the next file - `GLOBAL.uploadQueue` is where I keep a reference to all files I have to upload, `GLOBAL.uploadQueueIndexNextFile`

```
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
        didCompleteWithError:(nullable NSError *)error
{
    if ((error == nil && (GLOBAL.uploadQueueIndexNextFile < GLOBAL.uploadQueue.count - 1)) {
        // Not on last file, increment counter, start upload of next file
        speedLoggerResult = [NSString stringWithFormat:@"Transferring %i of %i files", (GLOBAL.uploadQueueIndexNextFile + 1), GLOBAL.uploadQueue.count];
        GLOBAL.uploadQueueIndexNextFile++; 
        [GLOBAL.fileProcessor processNextFileInUploadQueue];
    }
}

```

`processNextFileInUploadQueue` will prepare the file and call the convenience method for upload ((2) above).

Here are some sample output from caveman debugging (for file 2 - 4). **Notice, how as soon as app goes into background, upload stops.**

*Note, I've also waited longer than the 10 seconds shown in the output below. Longest was I left for dinner (30 minutes), came back and the upload ended up timing out. The OS never picked it up once the app is in the background.*

```
2016-02-21 05:53:01 +0000 | bkgd debug - about to start upload task | queueIndex: 2

2016-02-21 05:53:01 +0000 | in networking | totalBytesSent | 32768 of 233546 | queueIndex: 2

2016-02-21 05:53:01 +0000 | in networking | totalBytesSent | 65536 of 233546 | queueIndex: 2

2016-02-21 05:53:01 +0000 | in networking | totalBytesSent | 98304 of 233546 | queueIndex: 2

2016-02-21 05:53:01 +0000 | in networking | totalBytesSent | 131072 of 233546 | queueIndex: 2

2016-02-21 05:53:01 +0000 | in networking | totalBytesSent | 163840 of 233546 | queueIndex: 2

2016-02-21 05:53:01 +0000 | in networking | totalBytesSent | 196608 of 233546 | queueIndex: 2

2016-02-21 05:53:01 +0000 | in networking | totalBytesSent | 229376 of 233546 | queueIndex: 2

2016-02-21 05:53:01 +0000 | in networking | totalBytesSent | 233546 of 233546 | queueIndex: 2

2016-02-21 05:53:01 +0000 | in networking | didCompleteWithError | queueindex: 2

bkgd debug - processing next file

2016-02-21 05:53:02 +0000 | bkgd debug - about to start upload task | queueIndex: 3

2016-02-21 05:53:02 +0000 | in networking | totalBytesSent | 32768 of 1231286 | queueIndex: 3

2016-02-21 05:53:02 +0000 | in networking | totalBytesSent | 65536 of 1231286 | queueIndex: 3

2016-02-21 05:53:02 +0000 | in networking | totalBytesSent | 98304 of 1231286 | queueIndex: 3

2016-02-21 05:53:02 +0000 | in networking | totalBytesSent | 131072 of 1231286 | queueIndex: 3

2016-02-21 05:53:02 +0000 | in networking | totalBytesSent | 163840 of 1231286 | queueIndex: 3

2016-02-21 05:53:02 +0000 | in networking | totalBytesSent | 196608 of 1231286 | queueIndex: 3

2016-02-21 05:53:02 +0000 | in networking | totalBytesSent | 229376 of 1231286 | queueIndex: 3

2016-02-21 05:53:02 +0000 | in networking | totalBytesSent | 262144 of 1231286 | queueIndex: 3

2016-02-21 05:53:02 +0000 | in networking | totalBytesSent | 294912 of 1231286 | queueIndex: 3

2016-02-21 05:53:02 +0000 | in networking | totalBytesSent | 327680 of 1231286 | queueIndex: 3

2016-02-21 05:53:02 +0000 | in networking | totalBytesSent | 360448 of 1231286 | queueIndex: 3

2016-02-21 05:53:02 +0000 | in networking | totalBytesSent | 387704 of 1231286 | queueIndex: 3

2016-02-21 05:53:02 +0000 | in networking | totalBytesSent | 391392 of 1231286 | queueIndex: 3

2016-02-21 05:53:02 +0000 | in networking | totalBytesSent | 393216 of 1231286 | queueIndex: 3

2016-02-21 05:53:02 +0000 | in networking | totalBytesSent | 425984 of 1231286 | queueIndex: 3

2016-02-21 05:53:02 +0000 | in networking | totalBytesSent | 458752 of 1231286 | queueIndex: 3

2016-02-21 05:53:02 +0000 | in networking | totalBytesSent | 491520 of 1231286 | queueIndex: 3

2016-02-21 05:53:02 +0000 | in networking | totalBytesSent | 524288 of 1231286 | queueIndex: 3

2016-02-21 05:53:02 +0000 | in networking | totalBytesSent | 538768 of 1231286 | queueIndex: 3

2016-02-21 05:53:03 +0000 | in networking | totalBytesSent | 541664 of 1231286 | queueIndex: 3

2016-02-21 05:53:03 +0000 | in networking | totalBytesSent | 550352 of 1231286 | queueIndex: 3

2016-02-21 05:53:03 +0000 | in networking | totalBytesSent | 553248 of 1231286 | queueIndex: 3

2016-02-21 05:53:03 +0000 | in networking | totalBytesSent | 557056 of 1231286 | queueIndex: 3

2016-02-21 05:53:03 +0000 | App went into background.

2016-02-21 05:53:03 +0000 | in networking | totalBytesSent | 564832 of 1231286 | queueIndex: 3

2016-02-21 05:53:03 +0000 | in networking | totalBytesSent | 567728 of 1231286 | queueIndex: 3

2016-02-21 05:53:03 +0000 | in networking | totalBytesSent | 582208 of 1231286 | queueIndex: 3

2016-02-21 05:53:14 +0000 | in networking | totalBytesSent | 585104 of 1231286 | queueIndex: 3

2016-02-21 05:53:14 +0000 | in networking | totalBytesSent | 589824 of 1231286 | queueIndex: 3

2016-02-21 05:53:14 +0000 | in networking | totalBytesSent | 621680 of 1231286 | queueIndex: 3

2016-02-21 05:53:14 +0000 | App came into foreground. 

2016-02-21 05:53:14 +0000 | in networking | totalBytesSent | 622592 of 1231286 | queueIndex: 3

2016-02-21 05:53:14 +0000 | in networking | totalBytesSent | 655360 of 1231286 | queueIndex: 3

2016-02-21 05:53:14 +0000 | in networking | totalBytesSent | 688128 of 1231286 | queueIndex: 3

2016-02-21 05:53:14 +0000 | in networking | totalBytesSent | 720896 of 1231286 | queueIndex: 3

2016-02-21 05:53:14 +0000 | in networking | totalBytesSent | 753664 of 1231286 | queueIndex: 3

2016-02-21 05:53:14 +0000 | in networking | totalBytesSent | 786432 of 1231286 | queueIndex: 3

2016-02-21 05:53:14 +0000 | in networking | totalBytesSent | 819200 of 1231286 | queueIndex: 3

2016-02-21 05:53:15 +0000 | in networking | totalBytesSent | 851968 of 1231286 | queueIndex: 3

2016-02-21 05:53:15 +0000 | in networking | totalBytesSent | 884736 of 1231286 | queueIndex: 3

2016-02-21 05:53:15 +0000 | in networking | totalBytesSent | 887632 of 1231286 | queueIndex: 3

2016-02-21 05:53:15 +0000 | in networking | totalBytesSent | 893424 of 1231286 | queueIndex: 3

2016-02-21 05:53:15 +0000 | in networking | totalBytesSent | 917504 of 1231286 | queueIndex: 3

2016-02-21 05:53:15 +0000 | in networking | totalBytesSent | 939224 of 1231286 | queueIndex: 3

2016-02-21 05:53:15 +0000 | in networking | totalBytesSent | 950272 of 1231286 | queueIndex: 3

2016-02-21 05:53:15 +0000 | in networking | totalBytesSent | 970544 of 1231286 | queueIndex: 3

2016-02-21 05:53:15 +0000 | in networking | totalBytesSent | 983040 of 1231286 | queueIndex: 3

2016-02-21 05:53:15 +0000 | in networking | totalBytesSent | 1015808 of 1231286 | queueIndex: 3

2016-02-21 05:53:15 +0000 | in networking | totalBytesSent | 1048576 of 1231286 | queueIndex: 3

2016-02-21 05:53:15 +0000 | in networking | totalBytesSent | 1081344 of 1231286 | queueIndex: 3

2016-02-21 05:53:15 +0000 | in networking | totalBytesSent | 1114112 of 1231286 | queueIndex: 3

2016-02-21 05:53:15 +0000 | in networking | totalBytesSent | 1146880 of 1231286 | queueIndex: 3

2016-02-21 05:53:15 +0000 | in networking | totalBytesSent | 1179648 of 1231286 | queueIndex: 3

2016-02-21 05:53:15 +0000 | in networking | totalBytesSent | 1212416 of 1231286 | queueIndex: 3

2016-02-21 05:53:15 +0000 | in networking | totalBytesSent | 1231286 of 1231286 | queueIndex: 3

2016-02-21 05:53:16 +0000 | in networking | didCompleteWithError | queueindex: 3

bkgd debug - processing next file

2016-02-21 05:53:16 +0000 | bkgd debug - about to start upload task | queueIndex: 4

2016-02-21 05:53:16 +0000 | in networking | totalBytesSent | 32768 of 1278039 | queueIndex: 4

2016-02-21 05:53:16 +0000 | in networking | totalBytesSent | 65536 of 1278039 | queueIndex: 4

2016-02-21 05:53:16 +0000 | in networking | totalBytesSent | 98304 of 1278039 | queueIndex: 4

2016-02-21 05:53:16 +0000 | in networking | totalBytesSent | 131072 of 1278039 | queueIndex: 4

```

Happy to try anything at this point. Thanks!

EDIT #1
-------

Observed when background upload does work `application:handleEventsForBackgroundURLSession:completionHandler:` is called by the OS. Invariably that call back is never made when it doesn't work. 

I'm not sure if a prerequisite for background upload is the OS must kill the App first. If so, under what conditions does that happen? And can we prompt it?

As mentioned 49 times out of 50, OS will keep the app in the background, and upload is halted.