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

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

问题描述

我正在尝试在我的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天全站免登陆