在可重复使用的单元格中显示下载进度 [英] Displaying download progress in reusable cells

查看:12
本文介绍了在可重复使用的单元格中显示下载进度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to display download progress in my collectionview cells. Im currently using the parse progressblock which has an instance of the cell and updates the progress bar.

}, 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 元素都不可见,但进度仍在后台滴答作响.

So this works fine, the problem i now have is if i leave this view controller then come back to see how the downloads are going the instance of the cell has been reused and none of the desired UI elements are visible but the progress is still ticking away in the background.

我能想到的唯一重新显示 UI 元素的地方是 cellForItemAt.那么问题是进度不会更新,它只是显示重新加载单元格时的值.

The only place i can think to re-display the UI elements is in cellForItemAt. The problem then is that the progress doesn't update, it just shows the value at the time the cell was reloaded.

如何重新使用进度块正在使用的单元格实例或干净地显示继续更新的 ui 元素?

How can i go about reusing the instance of the cell that the progress block is using or cleanly displaying ui elements that continue to update?

推荐答案

假设你用集合视图解除旧的视图控制器并呈现一个新的,这里有两个问题:

Presuming that you're dismissing the old view controller with the collection view and presenting a new one, there are two problems here:

  • 然后,您尝试在前一个视图控制器中更新集合视图中的单元格;和

  • You're then trying to update cells in the collection view in the previous view controller; and

您对已关闭的旧视图控制器保持强烈引用.

You're keeping a strong reference to the old view controller that was dismissed.

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

If this is the case, the goal is to decouple the progress updates from any particular view controller, collection view, or cell. You also probably want to decouple the item/row number, too, in case you insert/remove any cells at any time. The best way to handle this is notifications:

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

  1. Define a few constants used when defining the notifications:

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:

  • Have your progressBlock post a notification rather than trying to update the UI directly:

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

    请注意,这里没有对 self 的引用,这可以防止进度块挂在您的视图控制器上.

    Please note that there are no reference to self here, which keeps the progress block from hanging on to your view controller.

    定义一些函数,您可以使用它来识别哪个 IndexPath 对应于您的下载标识符.在我的简单示例中,我将拥有一组下载标识符并使​​用它:

    Define some function that you can use to identify which IndexPath corresponds to the identifier for your download. In my simple example, I'm just going to have an array of download identifiers and use that:

    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 与您首次创建下载时的内容解耦很重要,以防您随时从集合视图中插入/删除任何项目.)

    You'd probably have a download identifier as a property of some Download model object, and use that instead, but hopefully it illustrates the idea: Just have some way to identify the appropriate IndexPath for a given download. (By the way, this decoupling the IndexPath from what it was when you first created the download is important, in case you insert/remove any items from your collection view at any point.)

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

    Now, you may ask what should you use for the identifier. You might use the URL's absoluteString. You might use some other unique identifier. But I'd discourage you from relying solely on item/row numbers, because those can change (maybe not now, but perhaps later as you make the app more sophisticated, you might be inserting removing items).

    让您的集合视图的视图控制器将自己添加为该通知的观察者,更新相应的进度视图:

    Have your collection view's view controller add itself as an observer of this notification, updating the appropriate progress 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] 捕获列表,以确保通知观察者不会导致视图控制器的强引用循环.

    Please note the [weak self] capture list, to make sure the notification observer doesn't cause a strong reference cycle with the view controller.

    这篇关于在可重复使用的单元格中显示下载进度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆