Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 91391|回复: 0

ios开发之解决重用TableViewCell导致的界面错乱的问题

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-4-11 18:48:59 | 显示全部楼层 |阅读模式

      无论是初学者,又或者是老鸟,只要是学习ios的人都知道,TableView对于开发有多重要,然而我们在使用TableView,可能会遇到各种各样的问题,例如今天我想要说的 TableViewCell的重用的问题:

      我们都知道,在TableView返回每一行cell的数据源方法中,我们一般会通过重用cell来达到节省内存的目的:通过为每个cell指定一个重用标识符(reuseIdentifier),即指定了单元格的种类,当cell滚出屏幕时,会将滚出屏幕的单元格放入重用的缓存池中,当某个未在屏幕上的单元格要显示的时候,就从这个缓存池中取出单元格进行重用。

    但对于多变的自定义cell,有时这种重用机制会出错。我举个简单的例子,看下面的两张图片 

    <1>正常显示的图片

     

     

    <2>界面错乱的图片

    通过比较以上两张图片 明显可以看出 第二张图片的界面显示错乱,原因很简单 ,那就是在重用cell的时候出现了问题,那么我们该怎么解决界面错乱或者其他的问题呢?下面我一一为大家来介绍:

     

    方法1 :

    将获得cell的方法从- (UITableViewCell*)dequeueReusableCellWithIdentifier:(NSString*)identifier 换为-(UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath

    重用机制调用的就是dequeueReusableCellWithIdentifier这个方法,方法的意思就是“出列可重用的cell”,因而只要将它换为cellForRowAtIndexPath(只从要更新的cell的那一行取出cell),就可以不使用重用机制,因而问题就可以得到解决,虽然可能会浪费一些空间。

    //下面是示例代码:

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

        static NSString *CellIdentifier = @"Cell"; 
        // UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; //改为以下的方法 
        UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; //根据indexPath准确地取出一行,而不是从cell重用队列中取出 
        if (cell == nil) { 
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 

    }......

    上面的代码,无疑是能够解决界面错乱的问题,但如果数据很多,那就会浪费相当多的空间,不推荐使用。

     

    方法2:

    为每个cell指定不同的重用标识符(reuseIdentifier)来解决。
    重用机制是根据相同的标识符来重用cell的,标识符不同的cell不能彼此重用。于是我们将每个cell的标识符都设置为不同,就可以避免不同cell重用的问题了。

    怎么为每个cell都设置不同的标示符呢?其实很简单 在返回每一行cell的数据源方法中 通过为每一个cell的标示符绑定indexPath.section--indexPath.row就可以了,下面是示例代码:

    //实现建立cell的具体内容

    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

        

        static NSString * ID = [NSString stringWithFormat:@"cell-ld%-ld%",[indexPath section ],[indexPath row]];

        //2.到缓存池中去查找可重用标示符

        HMWeiboCell * cell = [tableView dequeueReusableCellWithIdentifier:ID];

        if (cell == nil) {

            cell = [[HMWeiboCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];

        }

        //给cell中得属性framemodel赋值

        HMWeiboFrameModel * frameModel = self.weiboFrameArray[indexPath.row];

        cell.weiboFrameModel = frameModel;

        return cell;

    }

    //上面的这种方式 虽然说比第一种方式有了一定的改进,通过为每一个cell都绑定了一个不同的标识符能够使得cell与cell之间不会重用,解决了界面错乱的问题,但是从根本上来说还是没有太大的内存优化,同样的如果数据比较多还是比较浪费空间。

     

    方法3:

     

      第三种方式其实很简单就是删除重用cell的所有子视图,这句话什么意思呢?当我们从缓存池中取得重用的cell后,通过删除重用的cell的所有子视图,从而得到一个没有特殊格式的cell,供其他cell重用。是不是还是没懂什么意思,那我们就接着来看代码:

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

    {

        static NSString *ID = @"Cell";

        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; //出列可重用的cell

        if (cell == nil) {

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

        }

        else

        {

            //删除cell的所有子视图

            while ([cell.contentView.subviews lastObject] != nil)

            {

                [(UIView*)[cell.contentView.subviews lastObject] removeFromSuperview];//强制装换为UIView类型 ,移除所有子视图

            }

        }

        return cell;

    }  

      看完上面的代码是不是感觉这种方式很新颖,这种方式相比前两种方式来说 是比较完美的,既达到了重用的目的,又不会导致界面的错乱等问题,如果你也遇到了 自定义cell的时候 界面错乱不堪,不妨试试这种方式吧,你会觉得很神奇的... 

     

    方法4:

      看完了前面三种方式,你是不是觉得就没有后文了呢,你错了,下面我再来说说第四种方式:

      这第四种方式其实是比较笨的方法,为什么这么说呢,我们可以这么来想,既然重用cell导致界面错乱的原因是,重用cell的时候 数据没有更换,将重用cell的数据一起重用了,那么我们为什么想不到在给自定义cell设置数据的时候 通过判断每一个cell该使用什么样的数据呢 ,如果每一个cell使用的数据是不同的,那么就不会导致界面的数据或者是frame出现问题了,下面我就用简单的的例子来为大家演示:

     

        //如果是某一个软件的会员 那么会员图标的frame设置 如果不是会员那么重新设置 这样就能够解决会员图标的数据和frame问题

        if (weiboModel.vip) {//如果是会员

            CGFloat vipX = CGRectGetMaxX(_nameF) + kMargin;

            _vipF = CGRectMake(vipX, kMargin, kVipWidth, kVipWidth);

        } else{

            _vipF = CGRectZero;

        }

    再比如

        //设置picture的frame 注意也要判断是否有picture

        if (weiboModel.picture.length>0) {//有图片     

            CGFloat pictureY = CGRectGetMaxY(_textF) + kMargin;

            _pictureF = CGRectMake(kMargin, pictureY, kPictureWidth, kPictureWidth);

            //如果有图片行高就是最大的图片的y值加一个边距

            self.cellHeight = CGRectGetMaxY(_pictureF) + kMargin;

        }else {

            _pictureF = CGRectZero;   

            //如果没有图片 最大的行高就是正文的最大高度加一个高度

            self.cellHeight = CGRectGetMaxY(_textF) + kMargin;

        } 上面这句代码的目的是 当有图片的时候 给图片设置frame  如果没有图片那么我们就设置frame为0,这样就能轻松的解决frame导致的界面错乱的问题了。

      以上四种方式,有自己的拙见,也有借鉴网上各位大牛的方法,希望这篇文章能够对大家有帮助,有什么问题可以留言,我定将知无不言,言无不尽....

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-20 09:03 , Processed in 0.071433 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表