0

In my app I try to upload some data to a server when the app enters the background. This is the code I am using:

Session

self.session = [self backgroundSession];

This is how my session is set up

- (NSURLSession *)backgroundSession
{
    static NSURLSession *session = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.uploadSession"];
        configuration.HTTPMaximumConnectionsPerHost = 1;
        session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
    });
    return session;
}

Initiate upload

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    [self uploadPossibleDrives];
}

Upload

// Start uploading the remaing gps log in th right order:

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue setMaxConcurrentOperationCount:1];

for (int i = 0; i < arrayOfGPSLogChunks.count; i++)
{

    // This will ensure the chunks are sent in the right order
    // Add an operation as a block to a queue:

    [queue addOperationWithBlock: ^ {

        NSData *requestData;
        NSMutableURLRequest *request;

        if (i == 0)
        {
            NSLog(@"Initial drive upload %i",ID.integerValue);

            requestData = [NSJSONSerialization dataWithJSONObject:historyToUpload options:NSJSONWritingPrettyPrinted error:nil];
            request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:kInitialUploadDriveURL];
            [request setHTTPMethod:@"POST"];
            [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
            [request setValue:[NSString stringWithFormat:@"%d", [requestData length]] forHTTPHeaderField:@"Content-Length"];

        }
        else
        {
            NSLog(@"Chunk %i",i);

            NSMutableDictionary *chunk = [[NSMutableDictionary alloc] init];
            [chunk setObject:driveID forKey:@"driveID"];
            [chunk setObject:[arrayOfGPSLogChunks objectAtIndex:i] forKey:@"gpsLog"];

            requestData = [NSJSONSerialization dataWithJSONObject:chunk options:NSJSONWritingPrettyPrinted error:nil];
            request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:kUploadDrivesChunkURL]];
            [request setHTTPMethod:@"POST"];
            [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
            [request setValue:[NSString stringWithFormat:@"%d", [requestData length]] forHTTPHeaderField:@"Content-Length"];


        }

        NSLog(@"_session: %@",self.session);
        NSLog(@"request: %@",request);
        NSLog(@"requestData: %lu",(unsigned long)requestData.length);
        NSLog(@"uploadTask: %@",self.uploadTask);

        self.uploadTask = [self.session uploadTaskWithRequest:request fromData:requestData];
        [self.uploadTask resume];

        if (i == arrayOfGPSLogChunks.count-1)
        {
            // All gps logs were uploaded so now we save its state as 'uploaded to server':
            NSLog(@"Finished sending to server!");
            [self setSentToServerForDriveID:ID];
        }

    }];

}

Error

Now here is the error I get:

enter image description here

I do hope somebody can help me out. I have looked into everything I know but cant seem to figure out what ist going wrong. I also tried uploading without using the blocks but the result is the same.

Any help would be greatly appreciated!

freshking
  • 1,686
  • 15
  • 26
  • It seems there is a problem with backgroundSessionConfiguration. When I use `NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];` it theoretically works but obviously not in the background which is my objective. – freshking Apr 14 '14 at 10:52

1 Answers1

2

For a NSURLSession created with a backgroundSessionConfiguration, you have to use uploadTaskWithRequest:fromFile:.

See this question: NSURLSession and stream upload in background

Community
  • 1
  • 1
Isak
  • 1,383
  • 16
  • 21
  • I'm struggling to see this documented anywhere. In fact, I seem to be seeing the opposite. uploadTaskWithRequest:fromData: returns an NSURLSessionUploadTask. The [NSURLSessionUploadTask documentation](https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSURLSessionUploadTask_class/Reference/Reference.html#//apple_ref/occ/cl/NSURLSessionUploadTask) specifically says: "Unlike data tasks, you can use upload tasks to upload content in the background." – Matt Gibson Jul 31 '14 at 20:55
  • Yeah, it is poorly documented. But the documentation you point to does not contradict what I said. Just because you can use them in the background does not mean you can use whichever constructor you wish. See this question: http://stackoverflow.com/questions/19974673/nsurlsession-and-stream-upload-in-background – Isak Jul 31 '14 at 21:17
  • Ah, okay, I'm getting some of the subtlety in the wording now (I'm perfectly happy to accept what you say, by the way; I'm just really surprised there's not some fairly obvious and clear statement of it in the documentation that we can point to by now.) – Matt Gibson Jul 31 '14 at 21:20
  • Yeah it is pretty unfortunate, I've wasted a lot of time myself because of problems with the implementation and documentation. – Isak Jul 31 '14 at 21:25