UITableView中cell的重用机制

1.tableview实现机制(语言)解释

UITableView是很高效的,与它的cell复用机制密不可分。cell复用指的是什么呢?通俗地说一下。假设我们的tableview中有10个cell,窗口只容得下前5个,每个cell都是一样的,复用identifier也一样。从初始位置开始慢镜头,把cell前上滑动一点点,此时第一个cell的一部分消失了,第五个cell露出了一部分,这时第一个cell并没有进入到复用池,池子是空的,第五个cell自然也就不能在复用池中找到可复用的cell,第五个cell执行了如下代码:

[objc]  view plain  copy
  1. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cacheCellId];  
  2. if (!cell) {  
  3.     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];  
  4. }  

通过调试跟踪可以看到程序走到了if里面去。

当第五个cell完全显示出来,第一个cell也已经完全退出了窗口,这时第一个cell被放入到复用池。我们继续向上滑动,第六个cell将显示出来,它也要走上面的那段代码,但是它不会进入到if里面去,因为第一个cell已经在复用池中了,第六个cell可以复用第一个cell,而不需重新创建对象。


2.重用实现分析(代码)

  查看UITableView头文件,会找到NSMutableArray*  visiableCells,和NSMutableDictnery* reusableTableCells两个结构。visiableCells内保存当前显示的cells,reusableTableCells保存可重用的cells。

  TableView显示之初,reusableTableCells为空,那么tableView dequeueReusableCellWithIdentifier:CellIdentifier返回nil。开始的cell都是通过[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]来创建,而且cellForRowAtIndexPath只是调用最大显示cell数的次数。

  比如:有100条数据,iPhone一屏最多显示10个cell。程序最开始显示TableView的情况是:

  1. 用[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]创建10次cell,并给cell指定同样的重用标识(当然,可以为不同显示类型的cell指定不同的标识)。并且10个cell全部都加入到visiableCells数组,reusableTableCells为空。

  2. 向下拖动tableView,当cell1完全移出屏幕,并且cell11(它也是alloc出来的,原因同上)完全显示出来的时候。cell11加入到visiableCells,cell1移出visiableCells,cell1加入到reusableTableCells。

  3. 接着向下拖动tableView,因为reusableTableCells中已经有值,所以,当需要显示新的cell,cellForRowAtIndexPath再次被调用的时候,tableView dequeueReusableCellWithIdentifier:CellIdentifier,返回cell1。cell1加入到visiableCells,cell1移出reusableTableCells;cell2移出visiableCells,cell2加入到reusableTableCells。之后再需要显示的Cell就可以正常重用了。

  所以整个过程并不难理解,但需要注意正是因为这样的原因:配置Cell的时候一定要注意,对取出的重用的cell做重新赋值,不要遗留老数据。

3.解决cell重用遇到的问题

  1. 给每个cell做一个tag标记,对cell将要展示的差异内容进行判断
复制代码
 1 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 2     MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
 3     cell.myLabel.text = [NSString stringWithFormat:@"我的Label%ld", indexPath.row];
 4     cell.tag = indexPath.row;
 5     if (cell.tag == 5) {
 6         cell.imageVIew.backgroundColor = [UIColor greenColor];
 7     }
 8     if (cell.tag != 5) {
 9         cell.imageVIew.backgroundColor = [UIColor whiteColor];
10     }
11     return cell;
12 }
复制代码

  2.将cell的identifier设为唯一的, 保证了唯一性

1     NSString *identifier = [NSString stringWithFormat:@"%ld%ldcell", indexPath.section, indexPath.row];
2     MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];

  3.不使用系统的重用机制, 此方法在数据量较大时会造成过大的内存使用

1    MyTableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];

  4.删除将要重用的cell上的所有子视图, 得到一个没有内容的cell

 1 [(UIView*)[cell.contentView.subviews lastObject] removeFromSuperview]; 

4.是否需要注册cell

当重用cell时使用dequeue…… forindexpath:时需要注册cell,这样当需要新建cell时系统会利用runtime自动创建一个指定类型的cell

当重用cell时使用dequeue…… :时不需要注册cell,但是获取到的可能是cell == nil,所以这样写必须要判空cell。

参考网址:http://blog.csdn.net/huifeidexin_1/article/details/7678986,http://blog.csdn.net/worldzhy/article/details/42180729,https://www.cnblogs.com/yangkun852/p/5369943.html


猜你喜欢

转载自blog.csdn.net/lidongxuedecsdn/article/details/79602257