问题描述
NSURLSession
将允许您添加大量 NSURLSessionTask
以在后台下载。
如果您想检查单个 NSURLSessionTask
的进度,就像
double taskProgress =(double)task.countOfBytesReceived /(double)task.countOfBytesExpectedToReceive;
$ b b
但是,在 NSURLSession
所有 NSURLSessionTasks
> ?
我以为我会尝试平均所有任务的进度:
[[self backgroundSession] getTasksWithCompletionHandler:^(NSArray * dataTasks,NSArray * uploadTasks,NSArray * allDownloadTasks){
double totalProgress = 0.0;
for(NSURLSessionDownloadTask * task in allDownloadTasks){
double taskProgress =(double)task.countOfBytesReceived /(double)task.countOfBytesExpectedToReceive;
if(task.countOfBytesExpectedToReceive> 0){
totalProgress = totalProgress + taskProgress;
}
NSLog(@task%d:%.0f /%。0f - %.2f %%,task.taskIdentifier,(double)task.countOfBytesReceived,(double)task.countOfBytesExpectedToReceive, taskProgress * 100);
}
double averageProgress = totalProgress /(double)allDownloadTasks.count;
NSLog(@总进度:%.2f,平均进度:%f,totalProgress,averageProgress);
NSLog(@);
}];
但是这里的逻辑是错误的:假设你有50个任务需要下载1MB和3个任务期望下载100MB。如果50个小任务在3个大任务之前完成, averageProgress
将大大高于实际的平均进度。
因此,您必须根据 TOTAL countOfBytesReceived
TOTAL countOfBytesExpectedToReceive
。但问题是 NSURLSessionTask
只有在开始时才计算出这些值,并且它可能不会开始,直到另一个任务完成。
那么如何在所有 NSURLSessionTasks
> NSURLSession ?
在开始下载文件之前,您可以发送微小的 HEAD请求
获取文件大小。您只需添加他们的,并具有最终下载大小。
- (void)sizeTaskForURL:(NSURL *)url
{
NSMutableURLRequest * request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:@HEAD];
NSURLSessionDataTask * sizeTask =
[[self class] dataSession]
dataTaskWithRequest:request
completionHandler:^(NSData * data,NSURLResponse * response,NSError * error )
{
if(error == nil)
{
NSHTTPURLResponse * httpResponse =(NSHTTPURLResponse *)response;
if([httpResponse statusCode] == 200){
totalBytesExpectedToReceive + =(double)[httpResponse expectedContentLength];
numberOfFileSizesReceived ++;
NSLog(@%lu /%lu files found。file size:%f,(unsigned long)numberOfFileSizesReceived,(unsigned long)numberOfTasks,totalBytesExpectedToReceive);
if(numberOfFileSizesReceived == numberOfTasks){
NSLog(@%lu /%lu文件已找到,总文件大小:%f,(unsigned long)numberOfFileSizesReceived, numberOfTasks,totalBytesExpectedToReceive);
}
}
else {
NSLog(@URL状态下的大小任务的状态代码(%ld)%@,(长)[httpResponse statusCode] [response URL] absoluteString]);
}
}
else
{
NSLog(@Size task finished with error:%@,error.localizedDescription);
}
}];
[sizeTask resume];
}
之后下载文件
这是它的样子:
左边你可以看到当它发送 HEAD请求
它尚未启动
UIProgressView
。当它完成后,它下载文件。
所以如果你下载大文件,它可能是有用的浪费那些秒,使HEAD请求,从而向用户显示正确的进度,而不是一些错误的进展。 / p>
在下载过程中,你(绝对)想使用委托方法获得新数据的更小的细分(否则进度视图将跳转)。
An NSURLSession
will allow you to add to it a large number of NSURLSessionTask
to download in the background.
If you want to check the progress of a single NSURLSessionTask
, it’s as easy as
double taskProgress = (double)task.countOfBytesReceived / (double)task.countOfBytesExpectedToReceive;
But what is the best way to check the average progress of all the NSURLSessionTasks
in a NSURLSession
?
I thought I’d try averaging the progress of all tasks:
[[self backgroundSession] getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *allDownloadTasks) {
double totalProgress = 0.0;
for (NSURLSessionDownloadTask *task in allDownloadTasks) {
double taskProgress = (double)task.countOfBytesReceived / (double)task.countOfBytesExpectedToReceive;
if (task.countOfBytesExpectedToReceive > 0) {
totalProgress = totalProgress + taskProgress;
}
NSLog(@"task %d: %.0f/%.0f - %.2f%%", task.taskIdentifier, (double)task.countOfBytesReceived, (double)task.countOfBytesExpectedToReceive, taskProgress*100);
}
double averageProgress = totalProgress / (double)allDownloadTasks.count;
NSLog(@"total progress: %.2f, average progress: %f", totalProgress, averageProgress);
NSLog(@" ");
}];
But the logic here is wrong: Suppose you have 50 tasks expecting to download 1MB and 3 tasks expecting to download 100MB. If the 50 small tasks complete before the 3 large tasks, averageProgress
will be much higher than the actual average progress.
So you have to calculate average progress according to the TOTAL countOfBytesReceived
divided by the TOTAL countOfBytesExpectedToReceive
. But the problem is that a NSURLSessionTask
figures out those values only once it starts, and it might not start until another task finishes.
So how do you check the average progress of all the NSURLSessionTasks
in a NSURLSession
?
Before you start downloading the files you can send tiny small HEAD requests
to get the file-sizes. You simply add their expectedContentLength
and have your final download size.
- (void)sizeTaskForURL:(NSURL *)url
{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:@"HEAD"];
NSURLSessionDataTask *sizeTask =
[[[self class] dataSession]
dataTaskWithRequest:request
completionHandler: ^(NSData *data, NSURLResponse *response, NSError *error)
{
if (error == nil)
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if ([httpResponse statusCode] == 200) {
totalBytesExpectedToReceive += (double)[httpResponse expectedContentLength];
numberOfFileSizesReceived++;
NSLog(@"%lu/%lu files found. file size: %f", (unsigned long)numberOfFileSizesReceived, (unsigned long)numberOfTasks, totalBytesExpectedToReceive);
if (numberOfFileSizesReceived == numberOfTasks){
NSLog(@"%lu/%lu files found. total file size: %f", (unsigned long)numberOfFileSizesReceived, (unsigned long)numberOfTasks, totalBytesExpectedToReceive);
}
}
else {
NSLog(@"Bad status code (%ld) for size task at URL: %@", (long)[httpResponse statusCode], [[response URL] absoluteString]);
}
}
else
{
NSLog(@"Size task finished with error: %@", error.localizedDescription);
}
}];
[sizeTask resume];
}
Download the files afterwards
This is how it looks like:
On the left you can see that when it sends the HEAD requests
it does not yet start the UIProgressView
. When it has finished it downloads the files.
So if you download large files it might be useful to "waste" those seconds making HEAD requests and henceforth show the user the correct progress instead of some wrong progress.
During the downloads, you (definitely) want to use the delegate methods to get smaller subdivisions of new data (otherwise the progress view will "jump").
这篇关于NSURLSession中所有NSURLSessionTasks的平均进度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!