使用 NSProgress 查找下载速度和剩余时间



根据NSProgress的文档,我看到-[NSProgress localizedAdditionalDescription]可以报告下载速度和剩余时间,例如:

1.61 GB 的 3.22 GB(2 KB/秒)— 剩余 2 分钟

但是,当我将NSProgress关联到NSURLSessionDownloadTask时,我无法获得这些详细信息。这是我的代码:

下载器.h

@interface Downloader : NSObject
@property NSProgress *overallProgress;
-(void)startDownload;
@end

下载器.m

- (void)startDownload {
self.overallProgress = [NSProgress progressWithTotalUnitCount:100];
[self.overallProgress setKind:NSProgressKindFile];
[self.overallProgress setUserInfoObject:NSProgressFileOperationKindKey forKey:NSProgressFileOperationKindDownloading];

[self.overallProgress becomeCurrentWithPendingUnitCount:100];
[self work1];
[self.overallProgress resignCurrent];
}
- (void)work1 {
NSProgress *firstTaskProgress = [NSProgress progressWithTotalUnitCount:1];
[firstTaskProgress setKind:NSProgressKindFile];
[firstTaskProgress setUserInfoObject:NSProgressFileOperationKindKey forKey:NSProgressFileOperationKindDownloading];
NSURL *downloadURL = [NSURL URLWithString:@"http://ipv4.download.thinkbroadband.com/200MB.zip"];
NSURL *destinationDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject];
NSURL *destinationURL = [destinationDirectory URLByAppendingPathComponent:[downloadURL lastPathComponent]];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSURLSessionDownloadTask *fileDownloadTask =
[session downloadTaskWithURL:downloadURL
completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error){
[[NSFileManager defaultManager] removeItemAtURL:destinationURL error:NULL];
[[NSFileManager defaultManager] moveItemAtURL:location toURL:destinationURL error:nil];
[firstTaskProgress setCompletedUnitCount:1];
}];
[fileDownloadTask resume];
}

DownloadObserver.m

-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
downloader = [Downloader new];
[downloader addObserver:self
forKeyPath:@"overallProgress.fractionCompleted"
options:NSKeyValueObservingOptionNew
context:NULL];
[downloader startDownload];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
NSLog(@"%@", [downloader.overallProgress localizedAdditionalDescription]);
}

这只会打印出来:

0 的 100

100 字节的零 KB

如何localizedAdditionalDescription打印下载速度和剩余时间?

首先,totalUnitCount应该对应于文件的大小(以字节为单位)。在下载过程中,我们会更改反映在localizedAdditionalDescription上的completedUnitCountNSProgressKindFile提示将这些值格式化为文件大小。

为了正确设置进度,我们需要使用NSURLSessionDownloadDelegate方法而不是块处理程序。在 -URLSession: downloadTask: didWriteData: totalBytesWritten: totalBytesExpectedToWrite:中,我们拥有启动(totalBytesExpectToWrite)和更新(totalBytesWrite)进度的所有信息。

static void *myContext = &myContext;
- (void)download {
NSURL *downloadURL = [NSURL URLWithString:@"http://ipv4.download.thinkbroadband.com/10MB.zip"];
NSURLSession *session =
[NSURLSession
sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
delegate:self
delegateQueue:[NSOperationQueue mainQueue]];
[[session downloadTaskWithURL:downloadURL] resume];
}
#pragma mark - url session download delegate
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
if (!_progress) {
_progress = [NSProgress progressWithTotalUnitCount:totalBytesExpectedToWrite];
_progress.kind = NSProgressKindFile;
[_progress addObserver:self forKeyPath:@"fractionCompleted" options:0 context:myContext];
}
_progress.completedUnitCount = totalBytesWritten;
//[_overallProgress setUserInfoObject:@1024 forKey:NSProgressEstimatedTimeRemainingKey];
}
- (void)URLSession:(NSURLSession *)session 
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
[_progress removeObserver:self forKeyPath:@"fractionCompleted"];
_progress = nil;
NSLog(@"finished: %@", location);
}
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if (context == myContext) {
self.label.text = [_progress localizedAdditionalDescription];
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

事实上,NSProgress不做任何计算。它只是根据userInfo和其他类属性格式化本地化描述。请参阅文档中的常量部分。您可以使用这些值并比较本地化的描述输出。

如果要显示剩余下载时间,可以使用NSProgressEstimatedTimeRemainingKey。坏消息是您需要手动计算剩余时间。参考:如何(准确)估计剩余下载时间?

我尝试设置NSProgressThroughputKey,它以每秒字节数表示数据处理速度。我以为NSProgress会计算剩余时间,但它没有发生。

另请参阅 AFNetwork 源:AFURLSessionManagerTaskDelegate使用NSProgress实例执行上传和下载任务。

最新更新