ios - 在可重复使用的单元格中显示下载进度

标签 ios swift parse-platform uicollectionview uiprogressview

我正在尝试在我的 collectionview 单元格中显示下载进度。我目前正在使用具有单元格实例并更新进度条的解析进度 block 。

}, 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
    }
}
})

所以这工作正常,我现在遇到的问题是,如果我离开这个 View Controller ,然后回来查看下载情况,单元格的实例已被重用,并且没有任何所需的 UI 元素可见,但进度仍在滴答作响。

我认为唯一可以重新显示 UI 元素的地方是 cellForItemAt。那么问题是进度不会更新,它只显示重新加载单元格时的值。

我怎样才能重新使用进度 block 正在使用的单元格实例或干净地显示继续更新的 ui 元素?

最佳答案

假设您要用 Collection View 关闭旧 View Controller 并呈现一个新 View Controller ,这里有两个问题:

  • 然后您将尝试更新前一个 View Controller 中 Collection View 中的单元格;和

  • 您正在保留对已关闭的旧 View Controller 的强引用。

如果是这种情况,目标是将进度更新与任何特定的 View Controller 、 Collection View 或单元分离。您可能还想分离项目/行号,以防您随时插入/删除任何单元格。处理此问题的最佳方法是通知:

  1. 定义一些在定义通知时使用的常量:

    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"
    
  2. 让您的 progressBlock 发布通知,而不是尝试直接更新 UI:

    let percent: Float = ...
    let userInfo: [AnyHashable: Any] = [
        notificationIdentifierKey: identifier,
        notificationPercentKey: percent
    ]
    NotificationCenter.default.post(name: notificationName, object: nil, userInfo: userInfo)
    

    请注意,这里没有对 self 的引用,这可以防止进度 block 卡在您的 View Controller 上。

  3. 定义一些函数,您可以使用这些函数来识别哪个 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 与您首次创建下载时的内容分离很重要,以防您随时从 Collection View 中插入/删除任何项目。)

    现在,您可能会问应该使用什么作为标识符。您可以使用 URL 的 absoluteString。您可能会使用其他一些唯一标识符。但我不鼓励您仅依赖项目/行号,因为这些可能会改变(也许现在不会,但以后当您使应用程序变得更加复杂时,您可能会插入和删除项目)。

  4. 让您的 Collection View 的 View Controller 将自己添加为该通知的观察者,更新适当的进度 View :

    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] 捕获列表,以确保通知观察者不会导致与 View Controller 的强引用循环。

关于ios - 在可重复使用的单元格中显示下载进度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42181912/

相关文章:

ios - Parse.com - JSON 导入日期字段错误

ios - 调用 Selector 到 DismissViewController

ios - 如何使用自动布局调整 ScrollView 内容大小

javascript - 在空白行上获取内容可编辑的 UIWebView 中的插入符号

ios - ChatViewController 与协议(protocol)的冗余一致性

swift - 如何通过点表示法访问未实例化的对象? ( swift Playground )

ios - 目前尝试使用 Xcode 7.1 将 Parse 推送交织到我的 swift 应用程序中

android - 如何在 Parse.com android 上获取 objectId

ios - UIView加载/可见和卸载/消失时的方法

ios - iOS 是否有用于语音识别的内置开发者工具?