• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

ios - 使用 NSURLSessionDownloadTask 逐个下载文件

[复制链接]
菜鸟教程小白 发表于 2022-12-12 12:06:03 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题

在我的应用程序中,我从 Web 服务获取 JSON。此 JSON 包含我要下载的几个文件的 url。

我想使用 NSURLSessionDownloadTask 一个一个地下载每个文件(等待第一个下载完成,直到第二个开始,依此类推)。我还想跟踪写入的总字节数,以便更新 UI。

提前非常感谢!



Best Answer-推荐答案


众所周知,NSURLSessionDownloadTask 与 NSOperationQueues 的配合不太好,这与它们的对应物 NSURLConnection 不同(它可以封装在 NSOperation 中)。

一种选择是将所有 url 添加到一个数组中,然后在任务的 completionHandler 中,只需将下一个项目排队即可。

因此,您可以在循环中创建任务,在每个任务完成处理程序中调用 progressBlock,将任务存储在数组中,然后在每个任务完成处理程序中排队下一个任务:

- (void)addRequestsWithURLsNSArray *)urls
              progressBlockvoid (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations, NSURLSessionDownloadTask *task,NSURL *location, NSURLResponse *response, NSError *error))progressBlock {
    __block NSUInteger numberOfFinishedOperations = 0;
    NSUInteger totalNumberOfOperations = [urls count];
    for (NSString *url in urls) {
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
        __block NSURLSessionDownloadTask *task = [self.session downloadTaskWithRequest:request
                                                                completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
                                                                   //downloadFileSomewhere

                                                                    ++numberOfFinishedOperations;
                                                                        if (progressBlock) {
                                                                            progressBlock(numberOfFinishedOperations, totalNumberOfOperations,task,destination != nil ? [NSURL fileURLWithPath:destination] : nil,response,error);

                                                                        }
                                                                    //queueNext
                                                                    [self processCompletedTask:task];
                                                                }];
        //stores an array of NSURLSessionTasks
        [self.tasksWaitingToBeQueued addObject:task];
    }

}

- (void)processCompletedTaskNSURLSessionTask *)completedTask {
    //clean up and queue next one
    [self.tasksWaitingToBeQueued removeObject:completedTask];        
    nextTask = [self.tasksWaitingToBeQueued firstObject];
    if (nextTask) {
        [nextTask resume];
    }
}

注意

在此示例中,我将进度显示为完成的任务数而不是字节数,这是推荐的方法(也更简单)。要使用字节指示进度,您需要事先知道要下载的字节总数(因为您想显示进度条),还需要实现 NSURLSession 委托(delegate)并监控每个任务的进度,捕获下载的字节并更新您的 block .如果您的服务器没有告诉您总字节数,那么您可能需要对每个资源进行 HEAD 请求并汇总大小。就个人而言,这种解决方案很复杂,因为可以通过将进度指示为下载的文件数量来解决。

要实现这一点,可能看起来像这样:

- (void)URLSessionNSURLSession *)session 
      downloadTaskNSURLSessionDownloadTask *)downloadTask
      didWriteDataint64_t)bytesWritten
 totalBytesWrittenint64_t)totalBytesWritten
 totalBytesExpectedToWriteint64_t)totalBytesExpectedToWrite {
    self.totalBytesWritten += totalBytesWritten;
    NSUInteger totalProgressSoFar = self.totalBytesWritten;
    NSUInteger totalExpectedBytes = self.totalExpectedBytes;
    //you would need to capture some progress block locally - beware of retain cycles
    self.progressBlock(totalProgressSoFar/totalExpectedBytes)
}

当你完成后,你应该将 progressBlock 设置为 nil 到 prevent any retain cycles .

关于ios - 使用 NSURLSessionDownloadTask 逐个下载文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26297367/

回复

使用道具 举报

懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关注0

粉丝2

帖子830918

发布主题
阅读排行 更多
广告位

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap