NSURLSessionDownloadTask 进度回调不顺畅?
Posted
技术标签:
【中文标题】NSURLSessionDownloadTask 进度回调不顺畅?【英文标题】:NSURLSessionDownloadTask progress callback is not smoothly? 【发布时间】:2017-03-08 15:50:55 【问题描述】:我在前台通过NSURLSessionDownloadTask下载了一个文件,我需要在UI中显示当前的下载速度,
但我发现委托方法:URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:
调用不顺畅:
这样我可以显示准确的当前下载速度。
我确定这不是由服务器引起的。当我通过 ASIHTTPRequest 下载相同的文件时,没关系,进度块被顺利调用。
有人知道为什么吗?谢谢!
更新 #0:
委托方法的实现:
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
_totalReceived += bytesWritten;
NSLog(@"receive: %8.2f KB, total receive: %8.2f KB", bytesWritten / 1024.f, _totalReceived / 1024.f);
CFTimeInterval now = CFAbsoluteTimeGetCurrent();
if (_lastDataReceiveAt > 0.f)
CFTimeInterval delta = now - _lastDataReceiveAt;
NSLog(@"downloadtask: %p, speed: %8.2f KB/s; avg: %8.2f KB/s; delta time: %3.2fs",
downloadTask,
bytesWritten / 1024 / delta, _totalReceived / 1024 / (now - _beginsAt),
delta);
_lastDataReceiveAt = now;
//NSLog(@"downloading ... %.2f%%", totalBytesWritten * 100.f / totalBytesExpectedToWrite);
更新 #1:
嗨,@Rob,这是我的会话安装代码:
- (NSURLSession *)sessionWithIdentifier:(NSString *)identifier
if (identifier == nil)
NSString *bundleId = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"];
identifier = [NSString stringWithFormat:@"%@:///Downloader#%ld", bundleId, time(NULL)];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
//config.protocolClasses = @[ASIURLProtocol.class];
return [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
并且,下载任务初始化:
_session = [self sessionWithIdentifier:nil];
NSURL *url = ...;
_task = [_session downloadTaskWithURL:url];
[_task resume];
CFTimeInterval now = CFAbsoluteTimeGetCurrent();
_beginsAt = now;
_lastDataReceiveAt = now;
_totalReceived = 0;
【问题讨论】:
我测试了一些明显的可能性(会话队列的优先级;并发队列 v 串行队列;下载任务 v 数据任务;确保应用程序已达到静止状态;等等),但我没有发现任何问题。与URLSession
的通话只有一些情节延迟。如果 ASIHTTPRequest 没有受此影响,那可能只是 URLSession
和使用的任何 ASIHTTPRequest 之间的差异。我只是建议坚持使用URLSession
并使用一些尾随平均值或类似的东西,而不是依赖一个数据点来计算速度。
虽然我们在NSURLSession
委托方法中看到了一些偶发延迟,但通常以毫秒为单位,而不是 10 秒 (!)。我注意到您将主队列用于委托队列,如果您曾经阻塞主线程,您会看到您描述的那种行为。我建议将队列参数更改为nil
,看看这 10 秒的延迟是否会消失。但是,如果是这样,您确实应该返回并确定阻塞主线程的原因,因为它永远不应该被阻塞。
【参考方案1】:
这里的顺利是什么意思?他们不是以相同的时间间隔被调用吗?这是意料之中的。
您需要做的就是跟踪开始时间,并在回调中根据经过的时间和收到的数据计算速度。
如果这不是问题,请提供更多代码,也许是委托方法实现以及产生这些日志的原因。也许您还希望日志是什么?
【讨论】:
或者您可以只使用最近一次通话中收到的数据大小,以及自上次通话以来经过的时间,并使用它来确定速度。这将解决这个问题。 这不是他在做的吗?问题是一些进度更新有一点点延迟,所以当他只看最后一个数据点时,看起来速度波动很大。我建议介于“查看最后一个数据点”和“平均所有数据点”之间... 啊,对不起,我明白了。您可能想尝试一下最适合您的界面的方法,但有一些想法……您可以尝试一个简单的滑动窗口样式并查看最后的 X 块并在这些块上取平均值。或者,一个更好的主意是计算所有块的加权平均值。您可以为最近的块分配较低的权重,这样您仍然可以获得一个代表值,但最好考虑到速度变化的新近度。 @Rob 是的,这就是我想做的。但是委托方法不能称为“顺利”,一批数据在很短的时间内到达,然后,在很长一段时间(10秒?)之后,下一批数据在很短的时间内到达。所以速度波的形状突然上升,然后慢慢下降,然后又突然上升,周期性地。 @AlexLee - 10 秒有点极端,但是您的代码向我们展示了您在每次调用didWriteData
时计算的速度,我建议您在每次调用时计算速度,但是然后平均,例如,跟踪平均值中的最后 5 或 6 个,以使其专注于最近的速度,而不是仅仅依赖于最后一次调用。以上是关于NSURLSessionDownloadTask 进度回调不顺畅?的主要内容,如果未能解决你的问题,请参考以下文章
NSURLSessionDownloadTask 进度回调不顺畅?
在 NSMutableDictionary 中设置 NSURLSessionDownloadTask
NSUrlSessionDownloadTask - 进入后台时出现didCompleteWithError
iOS开发之网络编程--2NSURLSessionDownloadTask文件下载