[英]Displaying download progress in reusable cells
我试图在我的collectionview单元中显示下载进度。 我目前正在使用具有进度条的解析进度块,并更新进度条。
}, progressBlock: { (percent) in
self.mainQueue.addOperation {
// set the downloadProgess var to update from cellForItemAt
// downloadProgress = (Float(percent) / Float(100))
if let downloadingCell = self.collectionView.cellForItem(at: self.indexPath) as? InnerCollectionCell {
downloadingCell.progressBar.isHidden = false
downloadingCell.contentView.bringSubview(toFront: downloadingCell.progressBar)
downloadingCell.progressBar.setProgress(Float(percent) / Float(100), animated: true)
downloadingCell.setNeedsDisplay()
downloadingCell.setNeedsLayout()
downloadingCell.isUserInteractionEnabled = false
downloadingCell.spinner.isHidden = true
}
}
})
所以这很好用,我现在遇到的问题是,如果我离开该视图控制器,然后回来查看下载的进展情况,则该单元的实例已被重用,并且没有所需的UI元素可见,但进度仍在滴答作响在后台。
我能想到的重新显示UI元素的唯一位置是cellForItemAt。 然后的问题是进度不会更新,它只显示重新加载单元时的值。
我该如何重用进度块正在使用的单元格实例或干净显示继续更新的ui元素?
假设您要用集合视图关闭旧的视图控制器并显示一个新的视图控制器,这里有两个问题:
然后,您尝试在以前的视图控制器中更新集合视图中的单元格; 和
您对被关闭的旧视图控制器保持着强烈的参考。
在这种情况下,目标是将进度更新与任何特定的视图控制器,集合视图或单元分离。 您也可能还希望将项目/行号解耦,以防您随时插入/删除任何单元格。 最好的处理方法是通知:
定义在定义通知时使用的一些常量:
private let notificationName = Notification.Name(rawValue: "com.domain.app.downloadProgress") private let notificationIdentifierKey = "com.domain.app.download.identifier" private let notificationPercentKey = "com.domain.app.download.percent"
让您的progressBlock
发布通知,而不是尝试直接更新UI:
let percent: Float = ... let userInfo: [AnyHashable: Any] = [ notificationIdentifierKey: identifier, notificationPercentKey: percent ] NotificationCenter.default.post(name: notificationName, object: nil, userInfo: userInfo)
请注意,这里没有对self
引用,这使进度块无法挂接到视图控制器上。
定义一些函数,您可以用来识别哪个IndexPath
与您的下载标识符相对应。 在我的简单示例中,我将拥有一系列下载标识符,并使用该标识符:
var downloadIdentifiers = [String]() private func indexPath(for identifier: String) -> IndexPath? { if let item = downloadIdentifiers.index(of: identifier) { return IndexPath(item: item, section: 0) } else { return nil } }
您可能有一个下载标识符作为某些Download
模型对象的属性,而是使用了它,但希望它能说明这一思想:只需有某种方法IndexPath
以为给定的下载标识适当的IndexPath
。 (顺便说一句,如果您随时从集合视图中插入/删除任何项目,将IndexPath
与首次创建下载时的状态脱钩非常重要。)
现在,您可能会问应该使用什么作为标识符。 您可以使用URL的absoluteString
。 您可以使用其他一些唯一标识符。 但我不鼓励您仅依赖项目/行号,因为这些可能会更改(也许不是现在,但是可能稍后,当您使应用程序变得更加复杂时,您可能会插入删除项目)。
让您的集合视图的视图控制器将自身添加为该通知的观察者,从而更新适当的进度视图:
private var observer: NSObjectProtocol! override func viewDidLoad() { super.viewDidLoad() observer = NotificationCenter.default.addObserver(forName: notificationName, object: nil, queue: .main) { [weak self] notification in if let identifier = notification.userInfo?[notificationIdentifierKey] as? String, let percent = notification.userInfo?[notificationPercentKey] as? Float, let indexPath = self?.indexPath(for: identifier), let cell = self?.collectionView?.cellForItem(at: indexPath) as? InnerCollectionCell { cell.progressView.setProgress(percent, animated: true) } } ... } deinit { NotificationCenter.default.removeObserver(observer) }
请注意[weak self]
捕获列表,以确保通知观察者不会对视图控制器造成强烈的引用周期。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.