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

Posted

技术标签:

【中文标题】Swift:UIViewController 实例未从 URLSession 委托方法接收更新【英文标题】:Swift: UIViewController instance not receiving updates from URLSession Delegate methods 【发布时间】:2020-06-24 17:08:15 【问题描述】:

我无法从 URLSession Delegate 方法更新 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 Delegates 与我的 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 委托方法,他们实际上是尝试更新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】:

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

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

【讨论】:

感谢您的回答。您能否解释一下,对我来说最好的方法是什么?我应该为后台下载会话创建一个单例吗?如果是,那么我只需要在整个应用程序生命周期中进行一个后台 URL 会话。这对 UIViewController 的每个实例都有效吗?

以上是关于Swift:UIViewController 实例未从 URLSession 委托方法接收更新的主要内容,如果未能解决你的问题,请参考以下文章

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

Swift - 从 Nib 实例化总是返回 UIViewController 类型而不是动态类型

Swift:如何返回到我的 UIViewController 的同一个实例

UIViewController 实例问题

UIViewController 扩展从情节提要中实例化

-[UIViewController tableView:numberOfRowsInSection:]: 无法识别的选择器发送到实例