IOS开发—UITableView重用机制的理解

IOS开发—UITableView重用机制的理解





引言

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

假设某个UITableView100个数据需要显示,即需要100Cell,然而屏幕中最多只能一次性显示10Cell,那么有一个办法可以不用创建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就创建完成了。当需要第2cell的时候,同样也是先从重用队列里去取,发现还是没有,那么继续创建。可想而知,刚进到这个页面的时候需要创建10cell,且他们的标识符都是identifier

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

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

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

identifier

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

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];

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

可想而知,因为上面那段代码所有的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在入队的时候就会被放到不同的队列中,这样第一遍下拉100cell都是后每次调用dequeueReusableCellWithIdentifier都无法在对对应重用队列中找到cell,因此要创建100cell,这就增大了消耗。

注册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,运行后重复下拉上拉,会发现出现了列表混乱的现象! 

20150715224433832.png

 

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

方法一

将方法

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];

用下面方法替换

UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];

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

方法二

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

方法三

删除重用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;

}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值