iOS UITableViewCell重用机制理解之初级剑侠篇(欢迎提建议和分享遇到的问题)

本文主要是介绍iOS UITableViewCell重用机制理解之初级剑侠篇(欢迎提建议和分享遇到的问题),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

@dequeueResableCellWithIdentifier方法:这个单词翻译一下就是“出列的可重用的cell”

       iphone重用机制是苹果为了实现大量数据显示而采用的一种节省内存的机制,比如在UITableView和ScrollView 等地方。为什么要“可重用”?对于我们的项目来说,内存控制是必不可少的,如果一个tableview有几百个cell,这个内存消耗是很大的,而且有些cell里面都有image之类的很占内存的资源存在的话,那这样很容易出现memory warning甚至crash掉,这不是我们想要看到的。对
此,tableview实现了它自己的管理方法dequeueReusableCellWithIdentifier(ps:我们在某些项目中scrollview来显示很多张image,在scrollview滑动中也要这样处理,来避免内存的过度消耗,只不过tableview它已经实现了这个方法,而不用我们自己去写)。
       reuse机制:当cell需要显示的时候,从queue里面找,找到了,设置一下内容,显示出来滚动界面当有cell被移出屏幕时,把这个cell丢到queue里面。显示新的cell时,如果有“相同类型”(identifier)的cell,就从队列拿一个出来,设置数据,显示出来。至于queue里面会有多少cell,这个会自动控制。 其实也就是在"屏幕显示的cell数量"是有限的。当屏幕滚动时候,就会调用方法获取新的cell,而老的cell在屏幕外面就不显示了。

//对table view的数据进行绑定,即填充cell,自动调用n次
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {  
      
    static NSString *CellIdentifer = @"Cell";     //  0  
      

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:Cell];      //   1  


    if (cell == nil) {  

        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault  reuseIdentifier:CellIdentifer] ;    //  2  
    }  
      
    // Config your cell  
     cell.textlabel.text = @"XXX";    //  3  
      
    return cell;

    }

@可以这样理解,cell有一个地方(假设称为队列),专门存放那些生成过的,但是后来由于滚动tableView而隐藏起来的cell,而代码中语句1就是从队列中根据标示符取出一个暂时不用的cell,只有cell为nil,也就是队列中没有旧的cell的时候,才会执行语句2,生成一个新的cell。如果有旧的,就不用执行语句2了,这样节省资源,算作一种重用吧。在tableView初始化的时候队列中肯定没有cell的,所以每个cell生成的时候都会执行一遍2,当屏幕显示满了,向上滚动显示下一行时,就会把第一行隐藏,放到那个队列中,然后新增加的一行执行语句1的时候,结果就不是nil了,然后,就跳过语句2了,这样就节约资源了。

@当然,上面这样对于使用系统提供的cell格式是没有什么问题,但是如果自己在cell上添加一些控件时,比如一个label,有时就会出现问题。尤其是各个cell的label的文字不相同时。首先这个添加的过程一定要在语句2之后,这样才是一次添加,如果放在语句3之后,那么由于cell的重用可能旧的上面已经有label了,你再添加一个,造成多次添加。其次label的文本值必须保证每次都要重新设置,也就是在语句3之后设置,这样才能保证每次必须执行。如果放在语句2后面,那么当使用旧的cell时,仍会保留旧的label文字,这是不对的。所以是在2后添加,在3后设置,可以在2添加的时候设一个tag值,这样可以在3处通过tag值获取控件设置。


@插句话:如果用自己做的Cell的话,可以在初始化的时候设置,在赋值的时候设置数据,跟上面的意思一样


@关于语句0,如果每个cell的结构完全相同,那没问题,就用这一个标识符,但是如果各个cell结构不完全相同,有的有textfield,有的有button,有的有switch,那就不能互相重用了,只能每行用不同的标识符了,可以方便的利用(NSString *CellIdentifier = [NSString stringWithFormat:@"%@%U_%U",@"Cell",indexPath.section,indexPath.row];),保证不会重复,多组的再加上组号。那这还有必要用语句2吗?还是需要的,因为当自己滚动隐藏,下次再显示出来的时候,还是可以重用的。标识符完全可以每次用一个新的,但为了最大限度的重用性,节省资源,才想了这么多办法。

@总之,注意添加控件的位置,注意设置控件的位置,注意cell标识符。



uitableviewcell出错及解决办法,大家有更好的 可以提供分享啊


UITableView继承自UIScrollview,是苹果为我们封装好的一个基于scroll的控件。上面主要是一个个的UITableViewCell,可以让UITableViewCell响应一些点击事件,也可以在UITableViewCell中加入UITextField或者UITextView等子视图,使得可以在cell上进行文字编辑。


UITableView中的cell可以有很多,一般会通过重用cell来达到节省内存的目的:通过为每个cell指定一个重用标识符(reuseIdentifier),即指定了单元格的种类,当cell滚出屏幕时,会将滚出屏幕的单元格放入重用的queue中,当某个未在屏幕上的单元格要显示的时候,就从这个queue中取出单元格进行重用。

但对于多变的自定义cell,有时这种重用机制会出错。比如,当一个cell含有一个UITextField的子类并被放在重用queue中以待重用,这时如果一个未包含任何子视图的cell要显示在屏幕上,就会取出并使用这个重用的cell显示在无任何子视图的cell中,这时候就会出错。

解决方法:

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

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

示例代码:


[plain]
- (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]; 
    } 
     //...其他代码                               

- (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重用的问题了。

示例代码:


[plain]
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

     
    NSString *CellIdentifier = [NSString stringWithFormat:@"Cell%d%d", [indexPath section], [indexPath row]];//以indexPath来唯一确定cell 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; //出列可重用的cell 
    if (cell == nil) { 
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 
    } 
    //...其他代码 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   
    NSString *CellIdentifier = [NSString stringWithFormat:@"Cell%d%d", [indexPath section], [indexPath row]];//以indexPath来唯一确定cell
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; //出列可重用的cell
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
    //...其他代码
}

方法3 删除重用cell的所有子视图

这个方法是通过删除重用的cell的所有子视图,从而得到一个没有特殊格式的cell,供其他cell重用。

示例代码:


[plain]
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

    static NSString *CellIdentifier = @"Cell"; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; //出列可重用的cell 
    if (cell == nil) { 
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 
    } 
    else 
    { 
        //删除cell的所有子视图 
        while ([cell.contentView.subviews lastObject] != nil) 
        { 
            [(UIView*)[cell.contentView.subviews lastObject] removeFromSuperview]; 
        } 
    } 
    //...其他代码 


这篇关于iOS UITableViewCell重用机制理解之初级剑侠篇(欢迎提建议和分享遇到的问题)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1088522

相关文章

Vue3绑定props默认值问题

《Vue3绑定props默认值问题》使用Vue3的defineProps配合TypeScript的interface定义props类型,并通过withDefaults设置默认值,使组件能安全访问传入的... 目录前言步骤步骤1:使用 defineProps 定义 Props步骤2:设置默认值总结前言使用T

Web服务器-Nginx-高并发问题

《Web服务器-Nginx-高并发问题》Nginx通过事件驱动、I/O多路复用和异步非阻塞技术高效处理高并发,结合动静分离和限流策略,提升性能与稳定性... 目录前言一、架构1. 原生多进程架构2. 事件驱动模型3. IO多路复用4. 异步非阻塞 I/O5. Nginx高并发配置实战二、动静分离1. 职责2

解决升级JDK报错:module java.base does not“opens java.lang.reflect“to unnamed module问题

《解决升级JDK报错:modulejava.basedoesnot“opensjava.lang.reflect“tounnamedmodule问题》SpringBoot启动错误源于Jav... 目录问题描述原因分析解决方案总结问题描述启动sprintboot时报以下错误原因分析编程异js常是由Ja

Python内存优化的实战技巧分享

《Python内存优化的实战技巧分享》Python作为一门解释型语言,虽然在开发效率上有着显著优势,但在执行效率方面往往被诟病,然而,通过合理的内存优化策略,我们可以让Python程序的运行速度提升3... 目录前言python内存管理机制引用计数机制垃圾回收机制内存泄漏的常见原因1. 循环引用2. 全局变

MySQL 表空却 ibd 文件过大的问题及解决方法

《MySQL表空却ibd文件过大的问题及解决方法》本文给大家介绍MySQL表空却ibd文件过大的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录一、问题背景:表空却 “吃满” 磁盘的怪事二、问题复现:一步步编程还原异常场景1. 准备测试源表与数据

基于Redis自动过期的流处理暂停机制

《基于Redis自动过期的流处理暂停机制》基于Redis自动过期的流处理暂停机制是一种高效、可靠且易于实现的解决方案,防止延时过大的数据影响实时处理自动恢复处理,以避免积压的数据影响实时性,下面就来详... 目录核心思路代码实现1. 初始化Redis连接和键前缀2. 接收数据时检查暂停状态3. 检测到延时过

Redis中哨兵机制和集群的区别及说明

《Redis中哨兵机制和集群的区别及说明》Redis哨兵通过主从复制实现高可用,适用于中小规模数据;集群采用分布式分片,支持动态扩展,适合大规模数据,哨兵管理简单但扩展性弱,集群性能更强但架构复杂,根... 目录一、架构设计与节点角色1. 哨兵机制(Sentinel)2. 集群(Cluster)二、数据分片

解决Nginx启动报错Job for nginx.service failed because the control process exited with error code问题

《解决Nginx启动报错Jobfornginx.servicefailedbecausethecontrolprocessexitedwitherrorcode问题》Nginx启... 目录一、报错如下二、解决原因三、解决方式总结一、报错如下Job for nginx.service failed bec

SysMain服务可以关吗? 解决SysMain服务导致的高CPU使用率问题

《SysMain服务可以关吗?解决SysMain服务导致的高CPU使用率问题》SysMain服务是超级预读取,该服务会记录您打开应用程序的模式,并预先将它们加载到内存中以节省时间,但它可能占用大量... 在使用电脑的过程中,CPU使用率居高不下是许多用户都遇到过的问题,其中名为SysMain的服务往往是罪魁

MySQ中出现幻读问题的解决过程

《MySQ中出现幻读问题的解决过程》文章解析MySQLInnoDB通过MVCC与间隙锁机制在可重复读隔离级别下解决幻读,确保事务一致性,同时指出性能影响及乐观锁等替代方案,帮助开发者优化数据库应用... 目录一、幻读的准确定义与核心特征幻读 vs 不可重复读二、mysql隔离级别深度解析各隔离级别的实现差异