ios - 如何在 Swift 中将多个子进度聚合为一个主进度

标签 ios swift nsurlsession progress nsprogress

我正在尝试使用 Swift 中的 NSURLSession 同时下载多个文件。我想将所有下载进度状态合并为一个,以便在下载所有文件时显示 100%。目前,每个文件下载完成后我都会获得 100%,但只有在所有文件都已下载时我才需要 100%。我怎样才能在 Swift 中做到这一点?

这是我的下载管理器类:

class DownloadManager : NSObject, URLSessionDelegate, URLSessionDownloadDelegate {

static var shared = DownloadManager()
var task1Progress = 0.00
var task2Progress = 0.00
typealias ProgressHandler = (Float) -> ()

var onProgress : ProgressHandler? {
    didSet {
        if onProgress != nil {
            let _ = activate()
        }
    }
}

override private init() {
    super.init()
}

func activate() -> URLSession {
    let config = URLSessionConfiguration.background(withIdentifier: "\(Bundle.main.bundleIdentifier!).background")

    // Warning: If an URLSession still exists from a previous download, it doesn't create a new URLSession object but returns the existing one with the old delegate object attached!
    return URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue())
}

func calculateProgress(session : URLSession, completionHandler : @escaping (Float) -> ()) {
    session.getTasksWithCompletionHandler { (tasks, uploads, downloads) in
        let progress = downloads.map({ (task) -> Float in
            if task.countOfBytesExpectedToReceive > 0 {
                return Float(task.countOfBytesReceived) / Float(task.countOfBytesExpectedToReceive)
            } else {
                return 0.0
            }
        })
        completionHandler(progress.reduce(0.0, +))
    }
}


func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {

    if totalBytesExpectedToWrite > 0 {
        if let onProgress = onProgress {
            calculateProgress(session: session, completionHandler: onProgress)
        }

        let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
        debugPrint("Download Progress \(downloadTask) \(progress)")

    }
}

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
    debugPrint("Download finished: \(location)")
    try? FileManager.default.removeItem(at: location)
}


func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
    debugPrint("Task completed: \(task), error: \(String(describing: error))")
}

private func calculateProgress(session : URLSession, completionHandler : @escaping (Float) -> ()) {
    session.getTasksWithCompletionHandler { (tasks, uploads, downloads) in
        let progress = downloads.map({ (task) -> Float in
            if task.countOfBytesExpectedToReceive > 0 {

                if (task.taskIdentifier ==  1) {

                    self.task1Progress = Double(Float(task.countOfBytesReceived) / Float(task.countOfBytesExpectedToReceive))

                } else if (task.taskIdentifier ==  2){

                    self.task2Progress = Double(Float(task.countOfBytesReceived) / Float(task.countOfBytesExpectedToReceive))

                }

                print("pro1 = \(self.task1Progress) pro2 = \(self.task2Progress)")

                if(self.task1Progress>0.0000 && self.task2Progress>0.000) {
                    return Float(min(self.task1Progress  ,self.task2Progress))
                }

                return Float(max(self.task1Progress  ,self.task2Progress))

            } else {

                return 0.0
            }
        })
        completionHandler(progress.reduce(0.0, +))
    }
}

最佳答案

您可以使用 dispatchgroup tp 实现所需的行为。

要下载文件,您将调用 downloadManager 的共享方法。在 dispatchGroup 上调度下载操作,在通知中,您将在所有文件下载完成后收到回调。

请在下面找到示例:

func dispatchGroupUsage (completion: CallBack) {
let backgroundQ = DispatchQueue.global(attributes: .qosDefault)
let group = DispatchGroup()

for number in numberOfFilesToBeDownloaded {
  group.enter()
  backgroundQ.async(group: group,  execute: {  
      // call download manager's method to download files
      group.leave()

      })
  }

 group.notify(queue: DispatchQueue.main, execute: {
   print("All Done"); completion(result: fill)
 }) 
}

关于ios - 如何在 Swift 中将多个子进度聚合为一个主进度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49511459/

相关文章:

swift - 如何使用 URLSession 在异步 api 调用中查找哪个响应属于哪个请求

ios - 将变量设置为等于 View 的框架,而当 View 的框架更改时,值不会更改

ios - 如何检查两个非矩形图像的交集?

ios - 透明的 iOS 导航栏

ios - 如何在不使用库swift的情况下反序列化json响应类型

ios - NSURLSession 导致 0B 图像上传到 GCS

android - Flutter 嵌套 ListView.builder 抛出错误

ios - 在iOS播放下一首歌曲之前,我需要先停止MusicPlayerController吗?

pointers - 从指针中检索用户名对象 - Parse, swift

watchkit - 尝试在 watchOS 中进行后台刷新时不会调用 WKURLSessionRefreshBackgroundTask