引言

对于一个UITableView而言,可能需要显示成百上千个Cell,如果每个cell都单独创建的话,会消耗很大的内存。为了避免这种情况,重用机制就诞生了。

假设某个UITableView有100个数据需要显示,即需要100个Cell,然而屏幕中最多只能一次性显示10个Cell,那么有一个办法可以不用创建100cell,而只需要创建11(10+1)个。

理解

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
return cell;
}

我们来理解这段代码:

static NSString *identifier = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];

这两句代码的作用是:根据标识符identifier从重用队列中取出一个cell(先不用管重用队列是什么),由于一开始重用队列是空的,所以取出的cell也是空的,if(!cell)条件成立,就会去执行{}内的代码

cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];

创建UITableViewCellStyleDefault类型的cell,并将其标识为identifier(@”cell”);这样一个cell就创建完成了。当需要第2个cell的时候,同样也是先从重用队列里去取,发现还是没有,那么继续创建。可想而知,刚进到这个页面的时候需要创建10个cell,且他们的标识符都是identifier。

当我们下拉tableView,我们知道会出现第11个cell。这个时候还是先从重用队列里去取,发现没有,继续创建第11个cell并返回,这个时候,当第11个cell完全显示出来,第1个cell也刚好完全消失,它去哪了呢?第1个cell(标记为cell1)被放进重用队列了”。

再继续下拉,就要出现第12个cell了。那么还是继续创建吗?之前说过一共要创建11个cell,那么至此所有的cell都创建完毕了,那第12个cell是怎么来的呢?同样的,还是要先调用dequeueReusableCellWithIdentifier:方法,从重用队列中寻找cell,这个时候队列中有cell1,就会被取出来,这时候if(!cell)条件不成立,也就不会创建新的cell了,这个cell被返回作为第12个cell。可想而知,当第12个cell完全显示,第2个cell就完全消失进入重用队列了,再往下拉cell(2)就会作为第13个cell出现。就是这么神奇!

这就是重用机制,尽管需要100个cell,但事实上只创建了11个cell,这些cell重复利用,在需要的时候扮演不同的角色(只是换了件衣服,还是同一个人)。

identifier

可以看到在创建cell的时候伴随着一个identifier的绑定,这个identifier可以理解为这个cell标识,标识它属于哪个重用队列。

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];

再来看这句代码,从重用队列中取出一个cell,注意传入的参数identifier,如果把重用队列比作一个房间,那么identifier就好比这个房间的门牌号,标记着要从指定的房间去找人(也就是cell)。另外,入队的时候也会根据cell的identifier放到指定的重用队列中。

可想而知,因为上面那段代码所有的cell都用了相同的identifier,所以只会在一个重用队列中进进出出。假如把代码改成这样:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *identifier = [NSString stringWithFormat:@"cell%d",indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
return cell;
}

创建cell的时候对每个cell绑定不同的identifier,那么每个cell在入队的时候就会被放到不同的队列中,这样第一遍下拉100个cell都是后每次调用dequeueReusableCellWithIdentifier都无法在对对应重用队列中找到cell,因此要创建100个cell,这就增大了消耗。

注册cell

[_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:identifier];

可以在创建tableView的时候用这个方法注册cell,注册之后的作用是每次从重用列表中取cell 的时候,假如不存在,系统就会自动帮我们创建cell,并绑定标识符identifier。可想而知,注册之后就不需要再写这段代码了:

if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}

解决列表重复混乱问题

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(100, 0, 100, 50)];
label.text = [NSString stringWithFormat:@"测试%d%d%d",(int)indexPath.row,(int)indexPath.row,(int)indexPath.row];
[cell addSubview:label];
return cell;
}

我们对每个cell添加了一个子视图label,运行后重复下拉上拉,会发现出现了列表混乱的现象!

如果你理解了重用的本质,就不难知道其中的原因。简单的说,因为每次新出现的cell都是用过的,再对它添加label就是在原来已经有label的基础上又多了一个label,这就显示混乱了。解决方法如下:

方法一

将方法

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];

用下面方法替换

UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];

这种方法放弃了重用机制,每次根据indexPath获取对用的cell返回。

方法二

对每个cell设置不同的identifier,这种方式在前面介绍过,同样能解决列表重用的问题,虽然保留了重用机制,但是还是需要创建100个cell,性价比不高。

方法三

删除重用cell的子视图,即每次将cell从重用列表中取出重新使用的时候,先将其原有的所有子视图移除,这样就不会出现混乱了,这是方法保留了重用机制,且创建的cell数量最小化,性能比较高。代码如下:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
} //移除所有子视图
[cell.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
UIView *subView = (UIView *)obj;
[subView removeFromSuperview];
}];
//添加新视图
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(100, 0, 100, 50)];
label.text = [NSString stringWithFormat:@"测试%d%d%d",(int)indexPath.row,(int)indexPath.row,(int)indexPath.row];
[cell addSubview:label]; return cell;
}

至此,UiTableView的重用机制介绍完毕。

 

IOS开发—UITableView重用机制的了解的更多相关文章

  1. 操蛋的UITableView重用机制

    1,背景 你可能会遇见一下情况: 使用UITableView加载数据,比如你的每一个cell上面有一个UITextField,当你在第一个cell的UITextField中写下了内容,开始下滑UITa ...

  2. IOS之TableViewCell重用机制解决上下刷新重复显示

    首先我是一个经验浅薄的iOS开发人员,这个问题想必许多初学者经常遇到这些问题,在面试中也会经常问到.现在我们一一解决. 首先我们要知道TableViewCell重用机制的原理是什么,我们抽象的理解为古 ...

  3. iOS开发,UITableView相关问题

    第一条:UITableViewCell 内容的设置 //文本放到最后 NSIndexPath *indexPath = [NSIndexPath indexPathForRow:_dataArr.co ...

  4. UI之UItableView重用机制的性能问题

    *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...

  5. ios之TableViewCell重用机制避免反复显示问题

    常规配置例如以下 当超过tableView显示的范围的时候 后面显示的内容将会和前面反复 // 这样配置的话超过页面显示的内容会反复出现 - (UITableViewCell *)tableView: ...

  6. iOS开发UITableView基本使用方法总结

    本文为大家呈现了iOS开发中UITableView基本使用方法总结.首先,Controller需要实现两个delegate ,分别是UITableViewDelegate 和UITableViewDa ...

  7. iOS开发UITableView基本使用方法总结 分类: ios技术 2015-04-03 17:51 68人阅读 评论(0) 收藏

    本文为大家呈现了iOS开发中UITableView基本使用方法总结.首先,Controller需要实现两个delegate ,分别是UITableViewDelegate 和UITableViewDa ...

  8. IOS之TableViewCell重用机制避免重复显示问题

    常规配置如下 当超过tableView显示的范围的时候 后面显示的内容将会和前面重复. 1 // 这样配置的话超过页面显示的内容会重复出现 2 - (UITableViewCell *)tableVi ...

  9. iOS开发事件分发机制—响应链—手势影响

    1.提纲 什么是iOS的事件分发机制 ? 一个事件UIEvent又是如何响应的? 手势对于响应链有何影响? 2.事件分发机制 2.1.来源 以直接触摸事件为例: 当用户一个手指触摸屏幕是会生成一个UI ...

随机推荐

  1. 前端知识点-JS相关知识点

    1.谈谈你对Ajax的理解?(概念.特点.作用) AJAX全称为"Asynchronous JavaScript And XML"(异步JavaScript和XML) 是指一种创建 ...

  2. 伪AP检测技术研究

    转载自:http://www.whitecell-club.org/?p=310 随着城市无线局域网热点在公共场所大规模的部署,无线局域网安全变得尤为突出和重要,其中伪AP钓鱼攻击是无线网络中严重的安 ...

  3. CF Round #355 Div.2

    http://codeforces.com/contest/677 B. Vanya and Food Processor 题意:有一个食物加工器,每次能加工不超过h高度的土豆,且每秒加工至多k高度的 ...

  4. php获取url字符串截取路径的文件名和扩展名

    <?php //获取连接里边的id $url = 'http://www.rong123.com/cjbkscbsd/x_dfsdfs/24454_1_1.html'; function get ...

  5. Gentoo解决Windows系统txt文本中文乱码问题

    Linux与Windows系统语言编码区别 在Linux操作系统下,我们有时打开在windows下的txt文件,发现在windows下能正常显示的txt文件出现了中文乱码. 出现这种情况的原因为两种操 ...

  6. HTML5 <meta> 标签属性

    基本标签SEO 优化为移动设备添加 viewportWindows 8其他 禁止数字识自动别为电话号码不让android识别邮箱每 8 秒刷新一次页面移动端的头部标签和meta 基本标签 声明文档使用 ...

  7. Mac Java maven环境变量

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000; background-color: #fffff ...

  8. hadoop操作

    常用命令: https://hadoop.apache.org/docs/r1.0.4/cn/hdfs_shell.html ls命令 /usr/bin/hadoop/software/hadoop/ ...

  9. OC基础面试题

    1.iOS中delegate代理对象使用weak 之前不停的使用assign,今天在调试一段的时候,发现使用assgin的时候程序会crash,报错EXC_BAD_ACCESS, 经过一番研讨,发明如 ...

  10. svn 中commit时必须填写备注信息如何设置

    在软件开发团队中总是有人忘记添加备注信息,可以通过下面方式进行设置,从而在commit时强制需要填写备注信息. 在服务端选中需要设置的项目进行设置. 选中项目右键,"所以任务"-& ...