Swift:UIViewController实例未从URLSession委托方法接收更新

时间:2020-06-24 17:08:15

标签: ios swift nsurlsession

我无法通过URLSession代理方法更新UIViewController。

我有一个包含不同用户的TableView和一个详细视图控制器,其中包含与该用户关联的多个图像。

现在,我需要下载图像,然后创建一个具有每个用户唯一标识符的后台URL会话。我这样做是因为我必须为TableView中的每个用户使用相同的Detail UIViewController。

> DetailViewController

// Download service for this controller. Shared instance because it tracks active downloads. /// [URL:Download]

let downloadService:DownloadService = MediaDownloadManager.shared.downloadService


// A Unique background download session for each user

lazy var downloadSession: URLSession = {
    let identifer:String = "com.example.app" + "-user-" + userID   /// userID passed from parent
    let configuration = URLSessionConfiguration.background(withIdentifier: identifer)
    return URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
}()


override func viewDidLoad() {
    super.viewDidLoad()
    downloadService.downloadsSession = downloadSession

    /// I get this every time when I exit and re-enter the controller which is obvious.
    /// [DEBUG CONSOLE] A background URLSession with identifier com.example.app-user-12 already exists!
}

为了使下载进度和更新视图,我已将URLSession委托与DetailViewController兼容。

extension DetailViewController: URLSessionDelegate, URLSessionDownloadDelegate {
    func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) { /// }
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { /// }
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { /// }
}

现在的问题是,当我运行该应用程序并为用户打开DetailViewController并启动所需图像的下载过程时,它工作正常,并且我从urlsession委托方法获取更新,然后更新了我的tableView。

但是当我滑动回到TableViewController,然后为同一用户重新打开DetailViewController并开始下载图像时,DetailViewController的tableView不会从那些urlsession委托方法中接收更新。

我找到了引起此问题的确切原因。 URLSession代表 方法捕获我的视图控制器的实例。这意味着我什么时候 从URLSession更新我的DetailViewController的TableView 委托方法,他们实际上尝试更新表的 第一个和以前的UIViewController实例。

下面是更新单元进度的代码。

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
    guard let downloadURL = downloadTask.originalRequest?.url else {
        printAndLog(message: "### \(#function) Failed to retrieve original request download url", log: .network, logType: .error)
        return
    }
    let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
    let downloadedSize = ByteCountFormatter.string(fromByteCount: totalBytesWritten, countStyle: .file)
    let totalSize = ByteCountFormatter.string(fromByteCount: totalBytesExpectedToWrite, countStyle: .file)

    print(self) /// Same instance everytime.

    if let download = downloadService.activeDownloads[downloadURL] {
        download.progress = progress
        DispatchQueue.main.async {
            if let index = self.images.firstIndex(of: download.image),
                let cell = self.tableView.cellForRow(at: IndexPath(row: index, section: 0)) as? ImageCell {
                cell.updateProgress(progress: download.progress, loadedSize: downloadedSize, totalSize: totalSize)
            }
        }
    }
}

我该如何解决这个烦人的问题?我知道单身人士很好 回答,但我想尽可能避免单身。

我不能使用downloadSession.finishTasksAndInvalidate(),因为我认为退出控制器后将无法继续下载。

我的要求:

1-)退出控制器后,下载应继续。

2-)对于DetailViewController的每个实例,即对于每个用户,都应该可以下载

3-)当然,必须进行后台下载。

如果您认为该问题的标题有误,请原谅。

1 个答案:

答案 0 :(得分:1)

您需要添加另一个抽象级别。视图不应直接订阅后台下载过程。某些其他类应该订阅该视图,并且应该从该其他类中更新视图。

这样,即使有多个视图需要数据,也只有一次类订阅。

相关问题