TableView复用机制的坑
复用机制
UITableView
首先加载能够覆盖一屏幕的 UITableViewCell
(具体个数要根据每个 cell 的高度而定)。
然后当我们往上滑动时(往下滑动同理),需要一个新的 cell 放置在列表的下方。此时,我们不去生成新的 cell 而是先从 UITableView 的复用池里去获取,该池存放了已经生成的、能够复用的 cell ,如果该池为空,才会主动创建一个新的 cell 。
复用池的 cell 是这样被添加至该池的:当我们向上滑动视图时(向下滑动同理),位于最顶部的 cell 会相应地往上运动,直至消失在屏幕上。当其消失在视图中时,会被添加至当前 UITableView
的复用池。
因此,在渲染海量数据的列表时,并不需要很多 cell ,这得益于 UITableView
的复用机制。
问题
当我们没有显式地设置 cell 的样式和内容时,它会继续沿用回收前的样式和内容设置。
例如
当我将tableView下滑一段,再滑回来时,出现如下情况:
通过输出cell的description观察地址后发现,cell0重用了cell11的地址。
所以出现了内容还存在的情况,验证了很多个数据后发现复用池的数量比当前显示的cell数量略多一些。
原始代码:
TableViewController.swift
//
// TableVC.swift
// test123
//
//import UIKitclass 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.rowcell!.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 UIKitclass 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)