【问题标题】:What is the correct way to use prepareForReuse?使用 prepareForReuse 的正确方法是什么?
【发布时间】:2017-04-07 23:29:29
【问题描述】:

在了解如何在 UIKit 中使用 prepareForReuse() 方面需要帮助。 documentation

您应该只重置与不相关的单元格的属性 内容,例如 alpha、编辑和选择状态

但是如何重置单个属性属性,例如 isHidden?

假设我的单元格有 2 个标签,我应该在哪里重置:

  1. 标签.文本
  2. label.numberOfLines
  3. label.isHidden

我的 tableView(_:cellForRowAt:) 委托具有条件逻辑来隐藏/显示每个单元格的标签。

【问题讨论】:

    标签: ios swift uitableview prepareforreuse


    【解决方案1】:

    tldr:使用prepareForReuse 取消现有的网络调用,这些调用可以在下载不同的 indexPath 后完成。对于所有其他意图和目的,只需使用cellForRow(at:。这略微违反了 Apple 文档。但这就是大多数开发人员做事的方式。在两个地方都有单元配置逻辑很不方便......


    Apple 文档说用它来重置与内容相关的属性。然而,根据经验,在cellForRow 内为内容而不是不做所有事情可能更容易。唯一真正有意义的是

    Apple's docs 引用prepareForReuse

    出于性能原因,您应该只重置单元格的属性 与内容无关,例如 alpha、编辑和 选择状态。

    例如如果选择了一个单元格,您只需将其设置为未选择,如果您将背景颜色更改为某种颜色,则只需将其重置为 默认 颜色。

    tableView(_:cellForRowAt:) 中的 table view 的委托 应该 重用单元格时始终重置所有内容

    这意味着,如果您尝试设置联系人列表的个人资料图像,则不应尝试在 prepareforreuse 中设置 nil 图像,您应该正确地将图像设置在 cellForRowAt 中,如果您没有找到任何图像然后将其图像设置为nil 或默认图像。基本上,cellForRowAt 应该管理预期/意外状态。

    所以基本上以下是建议的:

    override func prepareForReuse() {
        super.prepareForReuse()
        imageView?.image = nil
    }
    

    建议使用以下方法:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            
        let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
    
         cell.imageView?.image = image ?? defaultImage // unexpected situation is also handled. 
         // We could also avoid coalescing the `nil` and just let it stay `nil`
         cell.label = yourText
         cell.numberOfLines = yourDesiredNumberOfLines
    
        return cell
    }
    

    另外推荐默认的非内容相关项目如下:

    override func prepareForReuse() {
        super.prepareForReuse()
        isHidden = false
        isSelected = false
        isHighlighted = false
        // Remove Subviews Or Layers That Were Added Just For This Cell
    
    }
    

    通过这种方式,您可以放心地假设在运行 cellForRowAt 时,每个单元格的布局都是完整的,您只需要担心内容。

    这是 Apple 建议的方式。但老实说,我仍然认为像马特所说的那样,将所有内容都倾倒在cellForRowAt 中更容易。干净的代码很重要,但这可能并不能真正帮助您实现这一目标。但是作为Connor said,唯一需要的是,如果您需要取消正在加载的图像。更多内容见here

    即做类似的事情:

    override func prepareForReuse() {
        super.prepareForReuse()
        
        imageView.cancelImageRequest() // this should send a message to your download handler and have it cancelled.
        imageView.image = nil
    }
    

    另外在使用 RxSwift 的特殊情况下: 见herehere

    【讨论】:

    • 但是,如果您根据单元格的数据属性将可变数量的视图添加到单元格的contentView 怎么办?不需要删除这些视图才能正确重置单元格的内容吗?在我的特定上下文中,这与集合视图更相关。
    • 您会(重新)为每个单元格设置变量编号吗?
    • 是的,data 属性是可选的,我在prepareForResue 中设置为nil,并且仅在属性不是nil 时添加视图。
    • 您不需要在prepareForCell 中执行此操作,只需在您的cellForRow 中为每个单元格设置数字或将其设置为nil。如果您不将其设置为nil,则单元格将仅使用放置在其中的最后一个数字
    • @Saranjith 我只是将这个函数命名为这样,以便与读者交流,您只会尝试将布局恢复到其原始状态。仅此而已
    【解决方案2】:

    如文档所述,您只需使用上述方法重置与内容无关的属性。至于重置标签的文本/行数....,您可以在设置新值之前从 tableView(_:cellForRowAt:) 中执行此操作,如下所示:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
        cell.label.text = "" //reseting the text
        cell.label.text = "New value"
        return cell
        }
    

    您可以采用更面向对象的方法,创建 UITableViewCell 的子类并定义一个方法,例如 configureCell() 来处理新出列单元格的所有重置和值设置。

    【讨论】:

    • 您无需在设置新值之前重置文本。只要您在cellForRowAt 中填充所有标签并设置所有 UI 状态,就无需“重置”简单属性。请参阅此问题的其他答案。
    猜你喜欢
    • 1970-01-01
    • 2021-11-24
    • 2021-09-23
    • 2013-01-09
    • 2013-03-19
    • 2019-05-11
    • 2018-02-17
    • 2022-01-07
    • 2012-05-17
    相关资源
    最近更新 更多