我正在尝试在我的集合视图单元格中显示下载进度。我当前使用解析进度块,它具有单元格的实例并更新进度栏。
}, 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
从您第一次创建下载时的情况来看,下载很重要,以防您随时从集合视图中插入/删除任何项目。)
现在,您可能会问应该使用什么标识符。您可能会使用 URLabsoluteString
。您可以使用其他一些唯一标识符。但我不鼓励您仅仅依赖项目/行号,因为这些可能会改变(也许现在不会,但也许稍后当您使应用程序变得更加复杂时,您可能会插入删除项目)。
-
让集合视图的视图控制器将自身添加为该通知的观察者,更新相应的进度视图:
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]
捕获列表,以确保通知观察者不会导致视图控制器的强引用循环。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)