最近在項目開發中遇到了一些關於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這樣。