3
- (NSURLSession *)sharedBackgroundSession
{
    static NSURLSession *sharedBackgroundSession = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.example.apple-samplecode.SimpleBackgroundTransfer.BackgroundSession"];
        configuration.URLCache = [NSURLCache sharedURLCache];
        configuration.requestCachePolicy = NSURLRequestReturnCacheDataElseLoad;
        sharedBackgroundSession = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
    });
    return sharedBackgroundSession;
}

// When executed on simulator, things work as expected, I never get a nil result.
// When executed on iPhone 5s device, nextDownloadTask is always nil
NSURLSessionDownloadTask *nextDownloadTask = [[self sharedBackgroundSession] downloadTaskWithRequest:request];

Any ideas?

UPDATE 9/12/14: I had this issue again, googled and found this SO post and then saw that I was the author of the question! This time around -URLSession:task:didCompleteWithError wasn't even getting called. THE SOLUTION WAS TO RESTART MY PHONE. This must be an Apple bug. I'm running iOS7 on my iPhone 5s.

John Erck
  • 9,478
  • 8
  • 61
  • 71
  • I was able to reproduce this very consistently about a half hour ago. However, now I can't reproduce it!! Which is great but frustrating too. `didCompleteWithError` was returning: *The operation couldn’t be completed. (NSURLErrorDomain error -999.)* when I was having issues. I couldn't ever figure out what error code -999 meant. Any ideas? – John Erck Mar 01 '14 at 15:52
  • I'm getting very similar behavior - sometimes it returns nil for a while, then sometimes it works just fine. All of my tests are on the device. It appears that many people have issues creating tasks in background sessions, but I have yet to find any answers about how to fix it. See https://devforums.apple.com/message/926113#926113 – jeremywhuff Mar 14 '14 at 20:56

4 Answers4

1

You should implement URLSession:task:didCompleteWithError: and it should report meaningful errors, if any.

In terms of sorts of issues that would work on simulator and not the device, they include (a) use of localhost in the URL; (b) use of URLs only available on LAN and iOS device not connecting successfully via wifi, e.g. perhaps only connecting via cellular; etc. You'd have to share more about the type of URL you are connecting to.

According to the documentation, NSURLErrorDomain error -999 is NSURLErrorCancelled. I'm unclear as to why you would get that particular error in this context, unless you were explicitly canceling the request or invalidating the session.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • I can confirm that I was not manually calling the `cancel` method on the download task or calling `invalidateAndCancel` on the background session. Still unsure as to the cause. If I find this error repeatable in the future and its specific cause, I will update this post accordingly. Thanks for your help!!! – John Erck Mar 01 '14 at 16:36
0

In my case, I was able to find a workaround for this problem:

1) Call the sharedBackgroundSession function

2) Call downloadTaskWithRequest on that session to test if the session is working properly, i.e. returning something non-nil

3) If #2 fails, then try again after a delay:

[_sharedBackgroundSession performSelector:@selector(sharedBackgroundSession) withObject:nil afterDelay:0.01];

In my case, the first attempt sometimes fails, sometimes succeeds. But the second attempt seems to reliably succeed.

jeremywhuff
  • 2,911
  • 3
  • 29
  • 33
0

I fixed this by calling [backgroundSession invalidateAndCancel]. I only had to call this once and after that I removed the code.

I'm now wondering if I should detect when tasks can no longer be created and call invalidateAndCancel before trying anymore tasks.

bentford
  • 33,038
  • 7
  • 61
  • 57
0
  1. Need to call invalidateAndCancel for your NSURLSession
  2. Set to nil your NSURLSession
  3. Create again NSURLSession
  4. Create again NSURLSessionDownloadTask

e.g.

NSURLSessionDownloadTask *dataTask = [self.yourSession downloadTaskWithRequest:urlRequest];
NSInteger attemptsNumber = 5;
for (NSUInteger attempts = 0; !dataTask && attempts < attemptsNumber; attempts++){
    [self.yourSession invalidateAndCancel];
    self.yourSession = nil;

    NSURLSessionConfiguration *backgroundConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:[[NSBundle mainBundle] bundleIdentifier]];
    self.yourSession = [NSURLSession sessionWithConfiguration:backgroundConfig delegate:self delegateQueue:nil];
    dataTask = [self.yourSession downloadTaskWithRequest:urlRequest];
}
gaRik
  • 607
  • 6
  • 10