在后台模式下下载操作队列不稳定的多个文件

Download multiple files with operation queue not stable in background mode

目前我想要实现的是从一个数组中下载文件,一次只下载一个文件,即使应用程序进入后台状态,它仍然执行下载。

我正在使用 中所述的 Rob 代码,但他正在使用 URLSessionConfiguration.default,而我想使用 URLSessionConfiguration.background(withIdentifier: "uniqueID") 代替。

它在第一次尝试时确实有效,但在它进入后台后一切都变得混乱了。操作开始一次下载多个文件并且不再按顺序下载。

是否有任何解决方案或我应该使用什么来实现我想要的。如果在 android 我们有服务可以轻松处理。

在操作中包装请求的整个想法仅适用于应用 active/running。这对于限制前台请求的并发度、管理依赖项等非常有用

不过,对于在应用暂停后继续进行的后台会话,none 是相关的。您创建请求,将其交给后台会话进行管理,并监视为后台会话调用的委托方法。无操作 needed/desired。请记住,这些请求将由后台会话守护程序处理,即使您的应用程序被暂停(或者如果它在其正常生命周期过程中终止,但如果您强制退出它则不会)。因此,如果后台 URLSession 守护程序正在处理请求并且您的应用程序未处于活动状态,那么整个操作、操作队列等概念就没有意义。

有关后台会话的示例,请参阅


顺便说一下,真正的后台会话在下载可能需要很长时间的非常大的资源时非常有用。但它引入了各种复杂性(例如,您经常希望在未连接到 Xcode 调试器时进行调试和诊断,这会改变您的应用程序生命周期,因此您必须求助于统一消息传递等机制;您需要弄清楚如何恢复 UI 如果应用程序在请求发起和完成之间终止;等等)。

由于这种复杂性,您可能需要考虑这是否绝对需要。有时,如果您只需要不到 30 秒即可完成某些请求,那么在用户离开应用程序后,让 OS 让您的应用程序 运行 在后台运行一会儿会更容易使用标准 URLSession。有关详细信息,请参阅 Extending Your App's Background Execution Time。这是一个更简单的解决方案,绕过了许多后台 URLSession 麻烦。但它仅在您只需要 30 秒或更短的时间时才有效。对于可能超过这个小 window 的更大请求,需要真正的背景 URLSession


下面,您问的是:

There are some downside with [downloading multiple files in parallel] as I understanding.

不,允许异步和并行下载总是更好。它速度更快,效率更高。唯一一次你想要一个接一个地连续请求,就是你需要解析一个请求的响应以便准备下一个请求。但这里不是这样。

此处的例外情况是默认的前景 URLSession。在那种情况下,您必须担心后面的请求超时等待前面的请求。在那种情况下,您可能会增加超时间隔。或者我们可以将我们的请求包装在 Operation 子类中,使我们不仅可以限制允许的并发请求数量,而且可以在较早的请求完成之前不启动后续请求。但即使在那种情况下,我们通常也不会按顺序进行,而是使用 maxConcurrentOperationCount of 4 或类似的东西。

但是对于后台会话,请求不会仅仅因为后台守护进程还没有处理请求而超时。只需将您的请求添加到后台 URLSession,然后让 OS 为您处理。您肯定不希望一次下载一个图像,当下载完成后,后台守护进程会在后台重新启动您的应用程序,以便您可以启动下一个。那将是非常低效的(无论是在用户的电池还是速度方面)。

You need to loop inside an array of files and then add to the session to make it download but It will be download asynchronously so it's hard to keeping track also since the files are a lot.

当然,如果请求是 运行 并行的,你不能天真地“添加到数组的末尾”,因为你不能保证它们完成的顺序。但是当它们进来时捕获这些响应并不难。例如,只需使用字典,可能由原始请求的 URL 键控。然后您可以轻松地在该字典中查找与特定请求关联的响应 URL.

非常简单。而且我们现在可以并行执行请求,速度更快,效率更高。

你接着说:

[Downloading in parallel] could lead the battery to be high consumption with a lot of requests at the same time. that's why I tried to make it download each file one at a time.

不,您永远不需要为了电量而一次下载一个。如果有的话,一次下载一个比较慢,而且会消耗更多电量。


无关,如果您要下载 800 多个文件,您可能希望允许用户在“低数据模式”下不执行这些请求。例如,在 iOS 13 中,您可以设置 allowsExpensiveNetworkAccess and allowsConstrainedNetworkAccess.

无论如何(特别是如果您支持旧的 iOS 版本),您可能还需要考虑适当的设置 isDiscretionary and allowsCellularAccess.

最重要的是,您要确保尊重用户有限的蜂窝数据计划,或者他们是否使用某些昂贵的服务(例如连接飞机的昂贵数据计划或通过某些本地热点连接)。

有关这些注意事项的更多信息,请参阅 WWDC 2019 Advances in Networking, Part 1