Recently, I encountered some problems about the UITableViewCell in the project development. When I repeatedly swiped the tableView, the contents of the cell changed. At the same time, I happened to see another article about this problem in nuggets recently. Reference and a bit of in-depth study of the UITableViewCell reuse mechanism, if there is a problem also please correct, improve together.
There are a lot of different opinions on this reuse mechanism. Most of them say that you can make a cell that covers a screen and then reuse it when you slide up and down. For example, when I slide down, I remove the view from the top cell and reuse it into the bottom cell. In this way, you only need to generate a little more than one screen of cells to achieve functionality and save resources.
After all, UITableView is not open source, how to implement it is not clear, so I made a small experiment, directly posted a code. Compilation environment: Xcode11.3.1, iOS13.2
//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) + It's added to the view) 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
}
}
Copy the code
//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() {// Note that dataLabel is not assigned when data is nullif data == "" {
indicateLabel.text = "No data at present"
} else {
indicateLabel.text = "Data available"
dataLabel.text = data
}
}
}
Copy the code
The following is a screenshot of the result.
I found that all 12 cells were generated. I made the height high for testing purposes. In fact, only 8-9 cells can be seen in the figure above.
This means that when the tableView calls the data source method, all the cells have been loaded. I’m not sure about this print. Maybe something happened to me. So also ask you gods to show one or two (manual clench fist
So as I pull down the view, I can see the cell reuse status as follows:
The first appearance of 9, 10 and 11 follows the figure above, so the second appearance of 9, 10 and 11 is the output result after the pull-down. It can be obviously found that the address of the new 9 cell is the same as that of the first 11 cell. It can be understood that the content of the first cell exposed downward is the last one reused from all the cells initially loaded, because at this time, the uppermost cell does not necessarily disappear and cannot be reused temporarily. Then the new 10 and 11 correspond to the 0 and 1 in the figure above and are reused from them to ensure that the top cell has disappeared and can no longer be seen.
At this point, scroll up again to find the reuse status update as follows:
It is easy to understand that 2, 1, and 0 appear on the screen in order from bottom to top. Comparing the above two figures, we can find that the 2 is not passive, while 1 and 0 are reused by 11 and 10, so there is a situation that may seem ridiculous at first glance:
Why is there data when there is no data? The reason for this and the solution to this problem can be found in this article, which was recently published. The content Settings of reusing cells do not change. When I do not explicitly specify the content of a control, reusing cells becomes problematic. In this example, the label value on the right side of the cell at address 11 and 10 is set to test. However, this result occurs when the code is reused to 1 and 0 because it does not explicitly assign a value to the label on the right side (no data). That article provided several solutions and discussed the pros and cons, but I would like to add that the cell can explicitly assign a value to the control in any case, thus avoiding this problem.
Ok, step on a small hole, also explore what cell reuse is really about. For this cell reuse, I am still not confident about my experimental results… Share, hope big guys offer more valuable advice.
When I increased the number of cells to 1000, I found that it was only printed to CELL18. Therefore, it can be speculated that all cells were not loaded in the memory before, and the number of multiplexing pools should be kept at twice the number that can be displayed on the current screen. If the total number of cells is less than the number of multiplexing pools, all cells will be loaded. And then we’re going to do the same thing, if we pull it down we’re going to take the last one in the pool and reuse it, which is 18, and then 0, 1, 2, and so on.