将请求包装在操作中的整个想法仅适用于应用程序处于活动/运行状态的情况。它非常适合限制前台请求的并发程度、管理依赖项等。
但是,对于在应用程序暂停后继续进行的后台会话,这些都无关紧要。您创建您的请求,将其交给后台会话进行管理,并监控为您的后台会话调用的委托方法。不需要/不需要任何操作。请记住,这些请求将由后台会话守护进程处理,即使您的应用程序已暂停(或者如果它在其正常生命周期过程中终止,但如果您强制退出它则不会)。因此,如果后台 URLSession 守护进程正在处理请求并且您的应用程序未处于活动状态,那么操作、操作队列等的整个想法就没有意义。
有关后台会话的示例,请参见 https://stackoverflow.com/a/44140059/1271826。
顺便说一句,真正的后台会话在下载可能需要很长时间的非常大的资源时非常有用。但它引入了各种复杂性(例如,您经常希望在未连接到 Xcode 调试器时进行调试和诊断,这会改变您的应用程序生命周期,因此您必须求助于统一消息等机制;您需要弄清楚如何恢复 UI如果应用程序在请求发起和完成之间终止;等等)。
由于这种复杂性,您可能需要考虑是否绝对需要这样做。有时,如果您只需要不到 30 秒的时间来完成某些请求,那么在用户离开应用程序后让操作系统让您的应用程序在后台运行一段时间并使用标准的URLSession 会更容易。有关详细信息,请参阅Extending Your App's Background Execution Time。这是一个更简单的解决方案,绕过了许多背景URLSession 的麻烦。但它仅在您只需要 30 秒或更短的时间时才有效。对于可能超出此小窗口的较大请求,需要真正的背景URLSession。
下面,你问:
据我了解,[并行下载多个文件]有一些缺点。
不,最好让下载以异步和并行的方式进行。它速度更快,效率更高。您唯一想要一个接一个地连续执行请求的地方是您需要解析一个请求的响应以准备下一个请求。但这里不是这样。
这里的例外是默认的前台URLSession。在这种情况下,您必须担心后面的请求会因等待较早的请求而超时。在这种情况下,您可能会增加超时间隔。或者我们可以将我们的请求包装在Operation 子类中,允许我们不仅限制我们将允许多少并发请求,而且在之前的请求完成之前不启动后续请求。但即使在这种情况下,我们通常也不会连续执行此操作,而是使用 4 的 maxConcurrentOperationCount 或类似的值。
但是对于后台会话,请求不会因为后台守护进程尚未处理它们而超时。只需将您的请求添加到后台URLSession 并让操作系统为您处理。你绝对不想一次下载一张图片,当一个下载完成后后台守护进程会在后台重新启动你的应用程序,这样你就可以启动下一个。这将是非常低效的(无论是在用户的电池方面还是在速度方面)。
您需要在文件数组中循环,然后添加到会话以使其下载,但它将异步下载,因此也很难跟踪,因为文件很多。
当然,如果请求是并行运行的,你不能简单地“添加到数组的末尾”,因为你不能保证它们完成的顺序。但是在这些响应进入时捕获它们并不难。例如,只需使用字典,可能由原始请求的 URL 键入。然后,您可以轻松地在该字典中查找与特定请求 URL 关联的响应。
这非常简单。而且我们现在可以并行执行请求,速度更快,效率更高。
你接着说:
[并行下载]可能会导致电池高消耗,同时请求很多。这就是为什么我试图让它一次下载一个文件。
不,您永远不需要为了电量而一次下载一个。如果有的话,一次下载一个会比较慢,而且会消耗更多的电量。
不相关,如果您要下载 800 多个文件,您可能希望允许用户在用户处于“低数据模式”时不执行这些请求。例如,在 iOS 13 中,您可以设置 allowsExpensiveNetworkAccess 和 allowsConstrainedNetworkAccess。
无论如何(特别是如果您支持较旧的 iOS 版本),您可能还需要考虑适当的设置 isDiscretionary 和 allowsCellularAccess。
归根结底,您要确保尊重用户有限的蜂窝数据计划,或者他们是否使用某些昂贵的服务(例如,使用飞机昂贵的数据计划连接或通过某些本地热点连接)。
有关这些注意事项的更多信息,请参阅WWDC 2019 Advances in Networking, Part 1。