最近在项目开发中遇到了一些关于UITableViewCell的问题,当我在反复滑动tableView的时候,cell上的内容出现了变更,同时我最近也恰好在掘金上看到了另一篇关于这个问题的文章,参考了一下并稍做深刻的研究了一下UITableViewCell的复用机制,若有问题还请指正,一块儿提升。swift
关于这个复用机制,网上众说纷纭,其中大部分的说法都是先生成能覆盖一屏幕的cell,而后上下滑动的时候再把这些cell复用,好比我向下滑的时候最上面的cell移除了视图,那么就把他复用为最下面的cell。这样只需生成略多于一屏幕的cell数量就能实现功能,还节省资源。bash
不过UITableView毕竟没有开源,具体怎么实现的也不清楚,因此搞了一个小小的实验,直接贴一段代码。
编译环境:Xcode11.3.一、iOS13.2ide
//TableViewController.swift
class TableViewController: UITableViewController {
let dataSourse = ["","","","","test","test","test","test","test","test","test","test"]
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(TestTableViewCell.self, forCellReuseIdentifier: TestTableViewCell.reuseIdentifier)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: TestTableViewCell.reuseIdentifier) as? TestTableViewCell
print("--------cell" + String(indexPath.row) + "被添加到视图中了")
cell!.data = dataSourse[indexPath.row]
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 dataSourse.count
}
}
复制代码
//TestTableViewCell.swift
class TestTableViewCell: UITableViewCell {
static let reuseIdentifier = "TestTableViewCell"
let indicateLabel = UILabel()
let dataLabel = UILabel()
var data: String! {
didSet {
display()
}
}
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
indicateLabel.frame = CGRect(x: 0, y: 30, width: 100, height: 40)
dataLabel.frame = CGRect(x: 100, y: 30, width: 100, height: 40)
contentView.addSubview(indicateLabel)
contentView.addSubview(dataLabel)
}
func display() {
//需注意的是在data为空的状况下并无对dataLabel进行赋值
if data == "" {
indicateLabel.text = "暂无数据"
} else {
indicateLabel.text = "有数据"
dataLabel.text = data
}
}
}
复制代码
打印结果截图以下。post
我发现全部的12个cell都生成了,我特意把高度拉的很高便于测试,事实上图中仅能看见8-9个cell。测试
这说明了在tableView调用该数据源方法时是将全部cell所有加载好了,对于这个打印结果,我其实也半信半疑,多是恰好某种状况让我撞见了?因此还请各位大神们指点一二(手动抱拳ui
那么随着我向下拉视图,能够发现cell的复用情况以下:spa
九、十、11的第一次出现是承接了上图,那么九、十、11的第二次出现即是下拉后的输出结果,能够明显的发现,这个新的9的cell是和第一次的11的地址是同样的,就能够理解为向下滑露出的第一个cell的内容是复用自最初加载的全部的cell的最后一个,由于此时最上面的cell还不必定消失,暂时不能被复用。那么新的十、11就和上图中的0、1对应,是复用自他们的,能够保证最上面的cell已经消失,再也不可以被看到。3d
此时再向上滑动,能够发现复用情况更新以下:code
很好理解,从下向上二、一、0按顺序出如今屏幕上,对照上面两图能够发现,这个2是没被动过的,而一、0是被十一、10复用过的,那么就出现了一个一开始看会以为很离谱的状况:cdn
明明原本没有数据的,为何又有了呢?关于这种状况出现的缘由和解决方案,能够看这篇文章,也是最近发布的一篇,大意为复用的cell的内容设置不会更改,当我没有显式的指定某个控件的内容,再进行复用就容易出问题。本例中十一、10地址的cell的右侧label值被设置为了test,而再复用到一、0中时因为代码并无显式的给右侧label赋值(无数据),就出现了这种结果。那篇文章提供了几个解决方案及其优劣讨论,我想补充一点的就是cell不管处于哪一种case均可以显式的给控件上一个值,这样就避免了这种问题的出现。
ok,踩了个小坑,也探究了cell复用究竟是怎么回事。对于这个cell复用,我仍是对个人实验结果不够自信。。。分享一下,但愿大佬们多提宝贵意见。
更新一下,当我把cell数量增到1000的时候,发现仅仅打印到cell18,由此能够推测出以前并非把全部的cell所有加载好放在内存中,复用池数量维持在当前屏幕可展现数量的两倍的状态,若是cell总数量小于复用池数量的话就所有加载。接下来的过程和以前同样,若是下拉的话是先把复用池中最后一个取出拿来复用,也就是18,而后是0、一、2这样。