4

我正在研究使用 NSURLSessionUploadTasks 来管理一些文件的后台上传。会话是使用以下方法创建的:

_urlsession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration backgroundSessionConfiguration:identifier] delegate:self delegateQueue:nil];

这是在符合 的类中创建的URLSessionDataTaskDelegate,并专门定义:

– URLSession:dataTask:didReceiveResponse:completionHandler:
– URLSession:dataTask:didBecomeDownloadTask:
– URLSession:dataTask:didReceiveData:

并在每次调用这些代表之一时登录到控制台。

然后,使用以下代码创建上传任务:

NSString *urlString = [NSString stringWithFormat:@"%@%@?filename=%@", HOST, UPLOAD_PATH, filename];
NSMutableURLRequest *attachmentUploadRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
attachmentUploadRequest.HTTPMethod = @"POST";
[attachmentUploadRequest addValue:@"application/binary" forHTTPHeaderField:@"Content-Type"];

NSURLSessionTask* task = [_urlsession uploadTaskWithRequest:attachmentUploadRequest fromFile:filePath];
task.taskDescription = 'upload';

但是,我得到的委托回调序列并不像预期的那样:

URLSession:didReceiveChallenge:completionHandler:]:196: Respond with <NSURLCredential: 0x1cf4fe00>:
URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]:282: Task 'upload' sent 32768 bytes
URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]:282: Task 'upload' sent 48150 bytes
URLSession:dataTask:didReceiveData:]:222: Task 'upload' got some data:

值得注意的是,正文数据按预期发送,但随后立即切换到didReceiveData委托回调,didReceiveResponse事先没有回调。这对我来说是一个意外的行为:我希望收到有关响应的信息,以便我可以正确设置数据,或者更好的是,将任务转换为下载任务以将响应保存到文件中。

如果上传任务在默认 URL 会话中提交,则调用 didReceiveResponse,我可以成功地将任务转换为后台下载任务。

我在 Apple 的文档中找不到任何关于是否didReceiveResponse应该为NSURLSessionUploadTask后台调用 s 的指示。似乎他们应该: 的文档表明它是 的子类,行为上做了一些小的修改,但列出的差异都没有涉及不发送回调。没有一个特定于背景会话的文档提到这个限制。NSURLSessionUploadTaskNSURLSessionDataTaskdidReceiveResponse

这是一个错误,还是错过/误解了一些解释后台上传任务不调用的文档didReceiveResponse

4

1 回答 1

6

I asked Apple engineers about this during recent Tech Talks. They followed up and gave the following response - not entirely satisfactory, and I feel like they should document this behavior if it is different than any other HTTP handling flow. Especially since the foreground behavior does get the didReceiveData, but doesn't get the didReceiveResponse. At the very least they need to document this non-obvious behavior.

"The way things work today is that we don’t send the didReceiveResponse callback for background uploads to avoid waking the app if it’s not already running. The drawback is that the app cannot choose to convert the background upload into a download task when the response is received. Our decision was based on expecting the response data for a file upload would be small and therefore delivering the response data to the client as NSData instead of a downloaded file would be fine."

于 2013-10-15T17:44:33.553 回答