swift - 我们可以在 swift 中分别使用多个 UIViewController 中的 URLSessionDelegate 方法同时下载文件吗

标签 swift

// Stores downloaded file
  func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
    // 1
    guard let sourceURL = downloadTask.originalRequest?.url else { return }
    let download = downloadService.activeDownloads[sourceURL]
    downloadService.activeDownloads[sourceURL] = nil
    // 2
    let destinationURL = localFilePath(for: sourceURL)
    print(destinationURL)
    // 3
    let fileManager = FileManager.default
    try? fileManager.removeItem(at: destinationURL)
    do {
      try fileManager.copyItem(at: location, to: destinationURL)
      download?.track.downloaded = true
    } catch let error {
      print("Could not copy file to disk: \(error.localizedDescription)")
    }
    // 4
    if let index = download?.track.index {
      DispatchQueue.main.async {
        self.tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .none)
      }
    }
  }

  // Updates progress info
  func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask,
    didWriteData bytesWritten: Int64, totalBytesWritten: Int64,
    totalBytesExpectedToWrite: Int64) {
    // 1
    guard let url = downloadTask.originalRequest?.url,
      let download = downloadService.activeDownloads[url]  else { return }
    // 2
    download.progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
    // 3
    let totalSize = ByteCountFormatter.string(fromByteCount: totalBytesExpectedToWrite,
      countStyle: .file)
    // 4
    DispatchQueue.main.async {
      if let trackCell = self.tableView.cellForRow(at: IndexPath(row: download.track.index,
        section: 0)) as? TrackCell {
        trackCell.updateDisplay(progress: download.progress, totalSize: totalSize)
      }
    }
  }

最佳答案

是的,基本思想是将 URLSessionDelegateUIViewController 解耦,并提供一种机制,URLSessionDelegate 可以通过该机制通知任何感兴趣的人在调用委托(delegate)方法时进行适当的更新。

我的首选模式是创建一个自定义共享 session 管理器,然后让它通知 View Controller (或发起下载的任何人)更新。有多种不同的机制可以通知 View Controller 您可以采用:

  • URLSessionDelegate 维护一个由任务标识符 (或 URL),例如:

    private var didWriteClosures: [Int: (URLSession, URLSessionDownloadTask, Int64, Int64, Int64) -> Void] = [:]
    private var didFinishClosures: [Int: (URLSession, URLSessionDownloadTask, URL) -> Void] = [:]
    

    当特定 View Controller 启动下载时,它会传递 session 管理器将保存在这些集合中的闭包。当主 session 管理器在 URLSessionDelegate 方法之一上获得回调时,它会获取任务标识符并有选择地调用正确的闭包。

  • 与上述方法类似,您可以在主 URLSessionDelegate 与发起请求的任何人之间采用您自己的委托(delegate)协议(protocol)模式。然后,主 URLSessionDelegate 可以维护这些委托(delegate)引用的集合,同样由任务标识符(或 URL)作为键控。

  • URLSessionDelegateNotificationCenter 上发布通知,然后让 View Controller 观察这些通知。

就个人而言,对于我只关心两个或三个委托(delegate)方法的简单接口(interface),我将使用第一种方法。当我怀疑我需要 URLSessionTaskDelegate 系列协议(protocol)的更大子集时,我倾向于使用第二种方法,然后我将采用委托(delegate)方法。

关于swift - 我们可以在 swift 中分别使用多个 UIViewController 中的 URLSessionDelegate 方法同时下载文件吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49542057/

相关文章:

swift - 为什么我的阴影在 SceneKit 中像素化/断断续续?

swift - 将具有特殊字符的字符串分隔成数组

swift - 如何使用 swift 2.2 watch 连接发送多个字典/多个 'application updates'

swift - 如何在 swift 4 Codable 中手动解码数组?

ios - Sprite 颜色在 Swift iOS 中没有改变

swift - 使用 FirebaseUI 和 Swift 自定义 TableViewCell

ios - 在主队列中设置属性时 Swift 应用程序崩溃

ios - 带有第一个字符的 NSPredicate 过滤器数组

ios - 如何使用原始索引路径从数组中删除对象?

ios - 如果键盘在 ios 应用程序中可见,如何以编程方式快速检查