Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSURLSession invalidateAndCancel: Bad Access

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

like image 309
LombaX Avatar asked Nov 16 '13 14:11

LombaX


1 Answers

  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.

like image 88
matt Avatar answered Oct 31 '22 02:10

matt