NSURLSession:方法 dataTaskWithRequest 永远不会在冗长的响应中到达完成回调
NSURLSession: method dataTaskWithRequest never reach completion callback on lengthy responses
以下代码用于创建与远程服务器和 send/receive HTTP requests/responses 的通信会话。
然而,当一个大文件附加到响应时,回调块从未到达。
只有在 NSURLSession 任务 (_dataTask) 超时后显式调用 cancel 方法时,才会调用此回调。
请注意,使用 tcpdump 可以很容易地观察到响应已在客户端正确接收。
NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
NSURLSession* session = [NSURLSession sessionWithConfiguration:config delegate:nil delegateQueue:queue];
_dataTask = [session dataTaskWithRequest:req completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if ([error code] == NSURLErrorCancelled) {
writeLog(LOG_ERROR, "NSURLErrorCancelled");
} else {
...
}
}];
[_dataTask resume]
// after timeout, the operation is cancelled.
sleep(100)
[_dataTask cancel];
我想知道使用 dataTask 是否有响应长度限制(因为它适用于响应主体上的小文件),如果有这样的限制,那么我应该使用哪种其他方法来克服它。
我看到 NSUrlsession 中有一个专门用于下载名为 downloadTaskWithRequest 的文件的替代方法,但它没有异步完成块。
谢谢!
获取大资源时,应该使用下载任务。数据任务将尝试在单个 NSData
对象中加载整个响应。同时在内存中加载大资产不仅效率低下,而且如果它非常大,可能会导致问题。
下载任务非常适合这些任务,因为它会为您将资产流式传输到临时文件,从而减少峰值内存使用量。 (诚然,您可以使用委托模式手动实现相同的数据任务,但下载任务会为您完成此操作。)
你说:
I saw that there's an alternative method in NSURLSession
dedicated for downloading files called downloadTaskWithRequest
but it doesn't have an async completion block.
两个观察:
有一个演绎 dataTaskWithRequest:completionHandler:
,它有一个完成块:
NSURLSession* session = [NSURLSession sharedSession];
NSURLSessionDownloadTask *task = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
...
}];
[task resume];
请注意,如果您不设置代理或以其他方式自定义 NSURLSession
,我建议您使用 sharedSession
。您不想不必要地实例化 NSURLSession
个对象。如果你真的必须实例化一个 NSURLSession
,为后续任务重新使用它 and/or 确保在提交该会话的最后一个任务后调用 finishTasksAndInvalidate
,否则 [=12= 】 会漏。而且,如果您实例化自己的 NSURLSession
,则不必实例化自己的操作队列,因为如果您不提供操作队列,它将默认为您创建一个串行队列。
没有块参数的再现,downloadTaskWithURL:
, works, too. All you need to do is to specify a delegate
for your NSURLSession
and then and implement URLSession:downloadTask:didFinishDownloadingToURL:
。
我建议这样做的原因是,通常,当我们下载非常大的资产(尤其是通过手机)时,我们意识到用户可能想要离开我们的应用程序并让下载在后台完成。在那些情况下,我们会使用背景 NSURLSessionConfiguration
。并且在使用后台会话时,您必须使用这种基于委托的方法。因此,如果您认为您最终可能会采用后台会话进行长时间下载,那么现在采用基于委托的方法是个不错的主意。
有关详细信息,请参阅 Downloading Files in the Background。
以下代码用于创建与远程服务器和 send/receive HTTP requests/responses 的通信会话。
然而,当一个大文件附加到响应时,回调块从未到达。
只有在 NSURLSession 任务 (_dataTask) 超时后显式调用 cancel 方法时,才会调用此回调。
请注意,使用 tcpdump 可以很容易地观察到响应已在客户端正确接收。
NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
NSURLSession* session = [NSURLSession sessionWithConfiguration:config delegate:nil delegateQueue:queue];
_dataTask = [session dataTaskWithRequest:req completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if ([error code] == NSURLErrorCancelled) {
writeLog(LOG_ERROR, "NSURLErrorCancelled");
} else {
...
}
}];
[_dataTask resume]
// after timeout, the operation is cancelled.
sleep(100)
[_dataTask cancel];
我想知道使用 dataTask 是否有响应长度限制(因为它适用于响应主体上的小文件),如果有这样的限制,那么我应该使用哪种其他方法来克服它。
我看到 NSUrlsession 中有一个专门用于下载名为 downloadTaskWithRequest 的文件的替代方法,但它没有异步完成块。
谢谢!
获取大资源时,应该使用下载任务。数据任务将尝试在单个 NSData
对象中加载整个响应。同时在内存中加载大资产不仅效率低下,而且如果它非常大,可能会导致问题。
下载任务非常适合这些任务,因为它会为您将资产流式传输到临时文件,从而减少峰值内存使用量。 (诚然,您可以使用委托模式手动实现相同的数据任务,但下载任务会为您完成此操作。)
你说:
I saw that there's an alternative method in
NSURLSession
dedicated for downloading files calleddownloadTaskWithRequest
but it doesn't have an async completion block.
两个观察:
有一个演绎
dataTaskWithRequest:completionHandler:
,它有一个完成块:NSURLSession* session = [NSURLSession sharedSession]; NSURLSessionDownloadTask *task = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) { ... }]; [task resume];
请注意,如果您不设置代理或以其他方式自定义
NSURLSession
,我建议您使用sharedSession
。您不想不必要地实例化NSURLSession
个对象。如果你真的必须实例化一个NSURLSession
,为后续任务重新使用它 and/or 确保在提交该会话的最后一个任务后调用finishTasksAndInvalidate
,否则 [=12= 】 会漏。而且,如果您实例化自己的NSURLSession
,则不必实例化自己的操作队列,因为如果您不提供操作队列,它将默认为您创建一个串行队列。没有块参数的再现,
downloadTaskWithURL:
, works, too. All you need to do is to specify adelegate
for yourNSURLSession
and then and implementURLSession:downloadTask:didFinishDownloadingToURL:
。我建议这样做的原因是,通常,当我们下载非常大的资产(尤其是通过手机)时,我们意识到用户可能想要离开我们的应用程序并让下载在后台完成。在那些情况下,我们会使用背景
NSURLSessionConfiguration
。并且在使用后台会话时,您必须使用这种基于委托的方法。因此,如果您认为您最终可能会采用后台会话进行长时间下载,那么现在采用基于委托的方法是个不错的主意。有关详细信息,请参阅 Downloading Files in the Background。