GCD:URLSession下载任务



我需要下载大量文件——以前一次只能下载一个文件。当前的设计是,当用户下载单个文件时,会创建URLSession任务,并使用URLSession的委托方法记录进度/完成/失败。我的问题是,如何在这种委托方法中离开调度组?我需要一次下载10个文件,在前10个文件完成时开始下一个10个文件。现在,如果我将调度组留在delegate方法中,那么调度组wait将永远等待。以下是我迄今为止实现的内容:

self.downloadAllDispatchQueue.async(execute: {
self.downloadAllDispatchGroup = DispatchGroup()
let maximumConcurrentDownloads: Int = 10
var concurrentDownloads = 0
for i in 0..<files.count
{
if self.cancelDownloadAll {
return
}
if concurrentDownloads >= maximumConcurrentDownloads{
self.downloadAllDispatchGroup.wait()
concurrentDownloads = 0
}
if let workVariantPart = libraryWorkVariantParts[i].workVariantPart {
concurrentDownloads += 1
self.downloadAllDispatchGroup.enter()
//call method for download
}
}
self.downloadAllDispatchGroup!.notify(queue: self.downloadAllDispatchQueue, execute: {
DispatchQueue.main.async {

}
})
})

在学员中:

func downloadDidFinish(_ notification: Notification){
if let dispatchGroup = self.downloadAllDispatchGroup {
self.downloadAllDispatchQueue.async(execute: {
dispatchGroup.leave()
})
}
}

这可能吗?如果没有,我如何才能做到这一点?

如果downloadAllDispatchQueue是串行队列,那么问题中的代码将死锁。当您调用wait时,它会阻塞当前线程,直到它从另一个线程接收到leave调用为止。如果您试图将leave调度到已经被wait调用阻塞的串行队列,它将死锁。

解决方案是根本不将leave调度到队列。没有必要这么做。直接从当前线程调用即可:

func downloadDidFinish(_ notification: Notification) {
downloadAllDispatchGroup?.leave()
}

下载大量文件时,我们通常使用后台会话。请参阅在后台下载文件。我们这样做是为了在用户离开应用程序后仍能继续下载。

当您开始使用后台会话时,不需要引入这种"十个一批"的逻辑。后台会话为您管理所有这些请求。对"十个一批"逻辑进行分层只会引入不必要的复杂性和低效率。

相反,我们只实例化一个后台会话并提交所有请求,然后让后台会话管理来自那里的请求。它简单、高效,甚至在用户离开应用程序后也能继续下载。如果你下载了太多文件,觉得需要这样管理它们,那么最终用户很可能会厌倦这个过程,并可能想在请求完成时离开应用程序去做其他事情。


相关内容

  • 没有找到相关文章

最新更新