【iOS】UITableViewCell的重用问题解决方法

我自己在实验中对cell的重用总结如下:

非自定义Cell和非自定义cell的复用情况一样:

  1. 第一次加载创建tableView的时候,是屏幕上最多也显示几行cell就先创建几个cell,此时复用池里什么都没有
  2. 开始下滑tableView,刚开始滑动时,由于第一行没有完全滑出屏幕进复用池时,下面的新cell已经显示到屏幕上了,所以下方这个新滑出来的cell就是新创建的cell而不是复用的cell(复用时也得看新加载的cell和复用池中的备用cell有没有同类型的id,没有就不复用),然后接着滑动,第一个cell就完全出屏幕进入复用池了,下面我们接着滑动,接着那个需要新显示出来的cell如果和复用池中我们保存的第一个cell是同种id,如果是就直接拿来复用,如果不是就新创建(判断是否能复用和新创建的操作都在cell的编辑函数:cellForRowAtIndexPath:中)
  3. 上滑tableView和下滑原理基本一致,完全出屏幕的入复用池,需要新加载到屏幕的cell,先看池中有没有同id的cell,有了就复用,没有就创建。

下面我们讲一个使用cell时需要注意的点:

复用时从复用池中取出来的cell可以是已经捆绑过数据或者加过子视图的,所以,如果有必要,要清除数据,比如(label的text)和remove掉add过的子视图(使用tag),否则就有可能造成复用后出现显示的内容不符预期的情况,比如说我们有一个开始创建id为@"test"的cell,我们在执行cell的编辑函数:cellForRowAtIndexPath:中有一个判断分支,符合某种情况时需要在cell上显示一个button,而不符合那种情况的时候就不显示button,而恰好我们这个cell符合情况,于是就添加了button相关的数据,然后显示出了button,接着我们滑动了tableView,导致我们刚才创建的这个id为@"test"的cell进入了复用池,然后再继续下滑的时候有一个新的id为@"test"的cell需要被加载出来,于是就查看了复用池,发现里面有同id的cell,所以就直接拿来复用了,复用的时候对里面的数据进行了自己的设定,本类好像没什么问题,但是恰好这个新cell不符合那个要显示button的条件,然后就不会去执行对button添加数据的操作,我们预想着这个新cell和之前我们创建的id为@"test"的cell的区别就是新的没有button,旧的有button,然后两者其他控件也就是数据内容不同(比如label的text不一样这些),但是实际情况却是这个新创建的cell上面显示的依然存在button,和我们预想的不一致,其原因就是复用时所取出来的旧cell是已经捆绑过数据且加过子视图的,虽然我们新cell创建时没有走对button添加数据的代码,但是由于旧cell走过了,且向button添加的数据都在,所以就导致新cell上面就有一个和旧cell一模一样的button。

这就是复用中可能存在的一个常见的难搞的问题,但是解决起来其实也非常简单,重点在于:避免重用机制出错

以下有三种方法:(最推荐第三种)

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

  2. 为每个cell指定不同的重用标识符(reuseIdentifier)来解决。重用机制是根据相同的标识符来重用cell的,标识符不同的cell不能彼此重用。

objc 复制代码
NSString *identifier = [NSString stringWithFormat:@"TimeLineCell%d%d",indexPath.section,indexPath.row];
  1. 在新cell创建走编辑函数:cellForRowAtIndexPath:时,在里面加一段操作,去remove多余的那个子视图或者清除旧数据

而且依我本人之见,最好使用清除旧数据而不是remove多余的子视图。因为这个正在新建的cell后面也许也会进入自动释放池,而且它到时候也可能会被拿来复用,如果那个复用它的cell刚好需要显示button而这个被复用的cell连button这个视图都没添加到cell上,那直接向button添加数据时程序就会crash,所以清除所有数据是不错的选择,反正每次执行编辑函数:cellForRowAtIndexPath:时都会为对应行组的cell重新添加那些子视图上的数据(相当于覆写了旧数据),我们只需要在所有的重新添加数据操作之前讲被复用的cell上子视图的数据全删了就行。

但是如果偏要走remove子视图的方法也不是不行,我们可以巧妙点,从复用池取出来要被复用的cell之后直接重新alloc初始化一下这个被复用的cell,相当于之前清空了原本保存的所有子视图的全部数据,而原本添加到cell上的子视图都还在,只是没有数据不显示罢了,这也是很好的手段。

相关推荐
職場上的造物主4 小时前
高清种子资源获取指南 | ✈️@seedlinkbot
python·ios·php·音视频·视频编解码·视频
Kevin Coding7 小时前
Flutter使用Flavor实现切换环境和多渠道打包
android·flutter·ios
wn5312 天前
【浏览器 - Mac实时调试iOS手机浏览器页面】
前端·macos·ios·智能手机·浏览器
小鹿撞出了脑震荡3 天前
Effective Objective-C 2.0 读书笔记—— 方法调配(method swizzling)
ios·objective-c·swift
小鹿撞出了脑震荡3 天前
Effective Objective-C 2.0 读书笔记—— 消息转发
ios·objective-c·swift
一丝晨光4 天前
Cocoa和Cocoa Touch是什么语言写成的?什么是Cocoa?编程语言中什么是框架?为什么苹果公司Cocoa类库有不少NS前缀?Swift编程语言?
macos·ios·objective-c·cocoa·swift·uikit·cocoa touch
LucianaiB7 天前
字节iOS面试经验分享:HTTP与网络编程
网络·ios·面试
黄油奥特曼7 天前
Flutter解决macbook M芯片Android Studio中不显示IOS真机的问题
flutter·ios·android studio·m芯片
taopi20247 天前
ios打包:uuid与udid
ios·iphone·ipad
小鹿撞出了脑震荡8 天前
Effective Objective-C 2.0 读书笔记——关联对象
开发语言·ios·objective-c