Question

I have a strange problem when I try to invalidate an NSURLSession instance. The code is quite simple: I have a View Controller, two buttons (start: and stop:), and a text field for the url.

A simple extract of the code:

- (IBAction)start:(id)sender {
    NSURLSessionConfiguration *conf = [NSURLSessionConfiguration backgroundSessionConfiguration:@"conf"];
    self.session = [NSURLSession sessionWithConfiguration:conf delegate:self delegateQueue:nil];
    NSURLSessionDownloadTask *task = [self.session downloadTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:self.url.text]]];
    [task resume];
}

- (IBAction)cancel:(id)sender {

    [self.session invalidateAndCancel];
}

or, if you prefer, the whole project: Link

Now, try to download a file ( http://download.thinkbroadband.com/1GB.zip ).

Since I want this download to continue in the background, I'm using a background session.
The session starts correctly and the download continue in the background, but if I try to cancel it (sending invalidateAndCancel) I have a bad access.
Profiling with Zombie enabled give this zombie object: _NSCFBackgroundDownloadTask.
So, if I retain the NSURLSessionDownloadTask (using a strong property to store it) the bad access doesn't happen. But, AFAIK, NSURLSession should retain it's tasks itself, so I would like to understand what's wrong with my code (maybe I'm missing something in the docs?) or if I should file a bugreport.

Thanks

Was it helpful?

Solution 2

After debugging a lot I found that it happens when the following NSURLSessionTaskDelegate protocol method is not implemented by the delegate:

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
}

Adding this method to the delegate solves the error. The "strange" thing is that the delegate method is marked as optional so It shouldn't be necessary. This makes me think that it's a bug, so I'll file a bugreport. I'll wait some days for more complete answers, then make mine as the correct one if no one appears.

EDIT:
if anyone is interested, I create an helper class-project to download files in background: Link To Project

OTHER TIPS

  1. Use a better background session configuration identifier, please! This is not really your session; a background session is a kind of gateway into a shared system session. You need to distinguish your session's tasks from those of all the other apps doing background uploading and downloading. Use something unique, like @"com.company.appname.specialname".

  2. Canceling and invalidating a background session doesn't make much sense. You are killing the session; you'll never be able to use it again after invalidating it. That's silly. What you want to do is create a background session once, as your app launches, and just leave it there forever (as a gateway to the shared system session, as I said before). What you want to cancel, if you want to cancel something, is the task. Keep a reference to the task so you can say cancel to that reference, if you think you're going to want to cancel it. Or, if you really don't want to keep a reference to the task, you can ask the NSURLSession for a list of your current tasks by calling getTasksWithCompletionHandler:; a task can have an identifier, so there should be no problem finding the one you want and telling it to cancel.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top