我有一个从网站下载文件的下载功能。除了从导航控制器点击后退按钮并尝试重新加载视图控制器之外,一切都很有效。下载任务在后台运行正常但在第二次重新加载时重置视图。这是我的代码。
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 myCell = self.tableView.cellForRow(at: IndexPath(row: Int(download.resource.resourceId - 1) ,
section: 0)) as? TranslationViewCell {
myCell.updateDisplay(progress: download.progress, totalSize: totalSize)
if download.isDownloading == true{
myCell.downloadButton.isHidden = true //this doesnt get activated at all.
myCell.reloadInputViews()
}
}
}
}
如果下载在后台运行,我试图隐藏下载按钮。
答案 0 :(得分:2)
当视图控制器从堆栈中弹出时,它将被取消分配。这意味着' self'您在代码中引用不再存在,这使得无法更新视图。
为了第二次正确加载视图,您需要在未解除分配的代码中保留下载任务,或者使用类似事件的内容来响应下载任务本身。
此时我们可以进入iOS应用程序架构的整个讨论;但是,我会给你我最喜欢的选择,让这个工作。
发送通知,而不是直接与tableview交互。代码可能看起来像这样......
首先扩展您自己的应用的通知类:
extension Notification.Name {
static let downloadProgressChanged = Notification.Name("download_progress_changed")
}
然后在回调期间发布通知:
DispatchQueue.main.async {
let notificationDict:[String: Download] = ["download": download]
NotificationCenter.default.post(name: .downloadProgressChanged, object: nil, userInfo: userDict)
}
然后你的视图控制器需要监听这些通知并适当更新,你应该在viewDidLoad中调用它
// MARK - Notifications
func setupListeners() {
NotificationCenter.default.addObserver(self, selector: #selector(handleProgressChanged(notification:)), name: .downloadProgressChanged, object: nil)
}
@objc func handleProgressChanged(notification: NSNotification) {
if let download = notification.userInfo?["download"] as? <whatever the class of Download is> {
// update the tableview here
}
}
现在你有一个视图控制器可以适当地响应这个下载任务,而不需要知道任何关于任务的信息。