9

当我尝试使NSURLSession实例无效时,我遇到了一个奇怪的问题。代码非常简单:我有一个视图控制器、两个按钮(开始:和停止:)和一个用于 url 的文本字段。

代码的简单摘录:

- (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];
}

或者,如果您愿意,可以选择整个项目:链接

现在,尝试下载一个文件 ( http://download.thinkbroadband.com/1GB.zip )。

由于我希望此下载在后台继续进行,因此我正在使用后台会话。
会话正确启动并在后台继续下载,但如果我尝试取消它(发送invalidateAndCancel),我的访问权限不正确。
启用 Zombie 的分析给出这个僵尸对象:_NSCFBackgroundDownloadTask.
因此,如果我保留NSURLSessionDownloadTask(使用强大的属性来存储它),则不会发生错误的访问。但是,AFAIK,NSURLSession 应该保留它本身的任务,所以我想了解我的代码有什么问题(也许我在文档中遗漏了一些东西?)或者我是否应该提交错误报告。

谢谢

4

2 回答 2

17
  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.

于 2013-11-16T15:16:11.687 回答
10

经过大量调试后,我发现当NSURLSessionTaskDelegate委托未实现以下协议方法时会发生这种情况:

- (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

于 2013-11-16T15:07:44.560 回答