TableView复用机制的坑

2023-12-15 22:41:17

TableView复用机制的坑

复用机制

UITableView 首先加载能够覆盖一屏幕的 UITableViewCell(具体个数要根据每个 cell 的高度而定)。

然后当我们往上滑动时(往下滑动同理),需要一个新的 cell 放置在列表的下方。此时,我们不去生成新的 cell 而是先从 UITableView 的复用池里去获取,该池存放了已经生成的能够复用的 cell ,如果该池为空,才会主动创建一个新的 cell 。

复用池的 cell 是这样被添加至该池的:当我们向上滑动视图时(向下滑动同理),位于最顶部的 cell 会相应地往上运动,直至消失在屏幕上。当其消失在视图中时,会被添加至当前 UITableView 的复用池。

因此,在渲染海量数据的列表时,并不需要很多 cell ,这得益于 UITableView复用机制

问题

当我们没有显式地设置 cell 的样式和内容时,它会继续沿用回收前的样式和内容设置

例如

当我将tableView下滑一段,再滑回来时,出现如下情况:

a6dd9d9af387d25665f241dcfa633e7d

通过输出cell的description观察地址后发现,cell0重用了cell11的地址。

所以出现了内容还存在的情况,验证了很多个数据后发现复用池的数量比当前显示的cell数量略多一些。

原始代码:

TableViewController.swift
//
//  TableVC.swift
//  test123
//
//

import UIKit

class TableVC: UITableViewController {

    let dataSource = ["", "", "", "", "test", "test", "test", "test", "test", "test", "test", "test", "test"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(TableViewCell.self, forCellReuseIdentifier: TableViewCell.reuseIdentifier)
        
        
        
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCell.reuseIdentifier) as? TableViewCell
//        let cell = TableViewCell(style: .default, reuseIdentifier: nil)
        
        print("---------cell\(indexPath.row)被添加到视图中了")
        
        cell!.cellOfIndex = indexPath.row
        cell!.data = dataSource[indexPath.row % dataSource.count]
        
        print(cell!.description)
        
        return cell!
    }
    
    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 100
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 100
    }
}

TableViewCell.swift
//
//  TableViewCell.swift
//  test123
//
//

import UIKit

class TableViewCell: UITableViewCell {
    
    static let reuseIdentifier = "TableViewCell"
    
    let indicateLabel = UILabel()
    let dataLabel = UILabel()
    var cellOfIndex: Int!
    
    var data: String! {
        didSet{
            display()
        }
    }
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        indicateLabel.frame = CGRect(x: 0, y: 30, width: 150, height: 40)
        dataLabel.frame = CGRect(x: 150, y: 30, width: 100, height: 40)
        
        contentView.addSubview(indicateLabel)
        contentView.addSubview(dataLabel)
    }

    required init?(coder: NSCoder) {
        fatalError()
    }
    
    func display(){
        if data == "" {
            indicateLabel.text = "cell\(cellOfIndex!)暂无数据"
            //显示设置
//            dataLabel.text = ""
        }else{
            indicateLabel.text = "cell\(cellOfIndex!)有数据"
            dataLabel.text = data
        }
    }

}

解决办法

1、取消复用机制,直接静态生成(资源消耗太多)

2、为每个cell根据indexPath设置唯一标识符(同上)

3、直接显式赋值呗(最easy)

文章来源:https://blog.csdn.net/yueliangmua/article/details/135025535
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。