URLSessionDownloadDelegate 似乎在不同线程中表现不佳

问题描述

我正在使用 URLSessionDownloadDelegate,特别是这种方法

func urlSession(_ session: URLSession,downloadTask: URLSessionDownloadTask,didFinishDownloadingTo location: URL)

从我的服务器获取完整的下载。

我刚刚完成了对我的应用程序的一组更改,以确保它不会同时更改其本地数据结构。我正在使用串行队列:

    let serialQueue = dispatchQueue(label: "MyLibrary")

对那些数据结构更改进行所有更改。

由于我的 URL 会话委托访问其中一些数据结构,我继续将所有代码封装在

func urlSession(_ session: URLSession,didFinishDownloadingTo location: URL)

在我的串行队列中。

然后我开始在我的应用中看到失败:

2021-02-28 19:32:17.105 [Error] [main] [ServerInterface.swift:101] userEvent(_:event:) > Optional(Error Domain=NSCocoaErrorDomain Code=512 "The file “SyncServer.A6590254-C807-46CD-B817-9A4D011CBD3A.dat” Couldn’t be saved in the folder “Temporary”." UserInfo={NSFileOriginalItemLocationKey=file:///private/var/mobile/Containers/Shared/AppGroup/4B605C28-FB25-4A4B-ACB1-BDCDD9D906AF/Documents/Temporary/SyncServer.A6590254-C807-46CD-B817-9A4D011CBD3A.dat,NSURL=file:///private/var/mobile/Containers/Shared/AppGroup/4B605C28-FB25-4A4B-ACB1-BDCDD9D906AF/Documents/Temporary/SyncServer.A6590254-C807-46CD-B817-9A4D011CBD3A.dat,NSFileNewItemLocationKey=file:///private/var/mobile/Containers/Shared/AppGroup/4B605C28-FB25-4A4B-ACB1-BDCDD9D906AF/Library/Caches/com.apple.nsurlsessiond/Downloads/biz.SpasticMuffin.SharedImages/CFNetworkDownload_LcEyLI.tmp,NSUnderlyingError=0x28155efa0 {Error Domain=NSCocoaErrorDomain Code=260 "The file “CFNetworkDownload_LcEyLI.tmp” Couldn’t be opened because there is no such file." UserInfo={NSURL=file:///private/var/mobile/Containers/Shared/AppGroup/4B605C28-FB25-4A4B-ACB1-BDCDD9D906AF/Library/Caches/com.apple.nsurlsessiond/Downloads/biz.SpasticMuffin.SharedImages/CFNetworkDownload_LcEyLI.tmp,NSFilePath=/private/var/mobile/Containers/Shared/AppGroup/4B605C28-FB25-4A4B-ACB1-BDCDD9D906AF/Library/Caches/com.apple.nsurlsessiond/Downloads/biz.SpasticMuffin.SharedImages/CFNetworkDownload_LcEyLI.tmp,NSUnderlyingError=0x28155d980 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}}})

当我删除上述 serialQueue 的这种用法时,问题不会发生。

我将进行更改,以便在使用 serialQueue 之前进行初始下载的文件访问(即,将文件移至我的控制之下),但我想知道为什么会这样。来自 URL 会话委托的文件访问是否特定于线程?即,以某种方式不是线程安全的?

谢谢!

解决方法

此委托方法的 documentation 声明 location 参数指定:

临时文件的文件 URL。由于该文件是临时文件,因此在从此委托方法返回之前,您必须打开该文件进行读取或将其移动到应用沙箱容器目录中的永久位置。

由于您在执行这些操作之前异步分派到串行队列,因此临时文件在您可以处理之前被删除。

例如,您可以在分派异步代码之前move the file to a new temporary location