一:首先查看一下关于UITableViewCell重用的定义

  1. - (nullable __kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;
  2.  
  3. - (__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);

在tableview新建的时候,会新建一个复用池(reuse pool).这个复用池可能是一个队列,或者是一个链表,保存着当前的Cell.pool中的对象的复用标识符就是reuseIdentifier,标识着不同的种类的cell.所以调用dequeueReusableCellWithIdentifier:方法获取cell.从pool中取出来的cell都是tableview展示的原型.无论之前有什么状态,全部都要设置一遍.

在UITableView创建同时,会创建一个空的复用池.之后UITableView在内部维护这个复用池.一般情况下,有两种用法,一种是在取出一个空的cell的时候再新建一个.一种是预先注册cell.之后再直接从复用池取出来用,不需要初始化.

第一种方法:

  1. - (nullable __kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;

UITableview第一次执行tableView:cellForRowAtIndexPath:.当前复用池为空.dequeueReusableCellWithIdentifier调用中取出cell,并检测cell是否存在.目前并不存在任何cell,于是新建一个cell,执行初始化, 并return cell.

代码如下:

  1. #define kInputCellReuseIdentifierPWD @"password_cell"
  2. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kInputCellReuseIdentifierPWD];
  3. if (!cell) {
  4. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kInputCellReuseIdentifierPWD];
  5. }
  6.  
  7. cell.textLabel.text = @"It is awesome";
  8. return cell;

上面的代码中,你返回的cell会被UITableView添加到复用池中.第二次调用tableView:cellForRowAtIndexPath:,当前复用池中有一个cell.这时候因为UITableView上面还未填满,而且复用池中唯一的那一个已经在使用了.所以取出来的Cell仍然是nil.于是继续新建一个cell并返回,复用池再添加一个cell,当前复用池中cell的个数为2.假如当前tableview只能容纳5个cell.那么在滚动到第6个cell时,从tableview的复用池取出来的cell将会是第0行的那个cell.以此类推,当滚动到第7行时,会从复用池取出来第1行的那个cell. 另外,此时不再继续往复用池添加新的cell.

第二种方法:

  1. - (__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);

在UITableView初始化的时候,注册一个UITableViewCell的类;不用再做空判断;

  1. [tableView registerClass:[BLSProjectMoneyCompleteCell class] forCellWithReuseIdentifier:NSStringFromClass([BLSProjectMoneyCompleteCell class])];

使用此方法之后,就不用再判断取出来的cell是否为空,因为取出来的cell必定存在.调用dequeueReusableCellWithIdentifier:方法时,会先判断当前复用池时候有可用复用cell.如果没有,tableview会在内部帮我们新建一个cell,其他的跟方法一一样

  1. BLSProjectMoneyCompleteCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([BLSProjectMoneyCompleteCell class])];

二:UITableViewCell重用时引发的问题

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

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

  1. 方法一:
  2.  
  3. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  4. {
  5. static NSString *CellIdentifier = @"Cell";
  6. // UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; //改为以下的方法
  7. UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; //根据indexPath准确地取出一行,而不是从cell重用队列中取出
  8. if (cell == nil) {
  9. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
  10. }
  11. //...其他代码
  12. }

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

  1. 方法二:
  2.  
  3. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  4. {
  5.  
  6. NSString *CellIdentifier = [NSString stringWithFormat:@"Cell%d%d", [indexPath section], [indexPath row]];//以indexPath来唯一确定cell
  7. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; //出列可重用的cell
  8. if (cell == nil) {
  9. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
  10. }
  11. //...其他代码
  12. }

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

  1. 方法三:
  2.  
  3. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  4. {
  5. static NSString *CellIdentifier = @"Cell";
  6. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; //出列可重用的cell
  7. if (cell == nil) {
  8. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
  9. }
  10. else
  11. {
  12. //删除cell的所有子视图
  13. while ([cell.contentView.subviews lastObject] != nil)
  14. {
  15. [(UIView*)[cell.contentView.subviews lastObject] removeFromSuperview];
  16. }
  17. }
  18. //...其他代码
  19. }

删除重用cell的所有子视图;这个方法是通过删除重用的cell的所有子视图,从而得到一个没有特殊格式的cell,供其他cell重用。考虑到内存问题,cell少得时候可以每个都添加标识符,当cell重用较多时,考虑内存问题,建议用删除cell的所有子视图方法(做视频播放的时候).

三: 有时Assertion failure in dequeueReusableCellWithIdentifier:forIndexPath: 闪退问题

在先前做的分组列表中,两组的Cell是不一样样式,两组分别运用如下的代码(也有在初始化注册Cell),在IOS9以下会闪退

  1. static NSString *CellIdentifier = @"Cell";
  2. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
  3. forIndexPath:indexPath];

后来修改成:

  1. static NSString *CellIdentifier = @"Cell";
  2. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
  3.  
  4. if (cell==nil) {
  5. cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
  6. }

四:prepareForReuse方法去重的效果

cell被重用如何提前知道? 重写cell的prepareForReuse官方头文件中有说明.当前已经被分配的cell如果被重用了(通常是滚动出屏幕外了),会调用cell的prepareForReuse通知cell.注意这里重写方法的时候,注意一定要调用父类方法[super prepareForReuse] .这个在使用cell作为网络访问的代理容器时尤其要注意,需要在这里通知取消掉前一次网络请求.不要再给这个cell发数据了.
// if the cell is reusable (has a reuse identifier), this is called just before the cell is returned from the table view method dequeueReusableCellWithIdentifier:. If you override, you MUST call super.

  1. - (void)prepareForReuse
  2. {
  3. [super prepareForReuse];
  4. }

自定义UITableViewCell的方法有很多 发现一些人都会遇到自己定义的cell里面图片错乱的问题 这个问题往往是因为没有实现prepareForReuse这个方法导致的.

UITableViewCell在向下滚动时复用, 得用的cell就是滑出去的那些, 而滑出去的cell里显示的信息就在这里出现了 解决的方法就是在UITableViewCell的子类里实现perpareForReuse方法, 把内容清空掉,就可以对控件进行清空,实现被重复增加的问题;

  1. -(void)prepareForReuse
  2. {
  3. [super prepareForResuse];
  4.  
  5. _titleLb.text = nil;
  6. _commentLabel.text = nil;
  7. _standarLabel.text = nil;
  8. _photos = nil;
  9.  
  10. _line1.hidden = YES;
  11. _line2.hidden = YES;
  12. for (UIView *view in _imgViews.subviews) {
  13. if (view.tag > && ([view isKindOfClass:[UIImageView class]]||[view isKindOfClass:[UILabel class]])) {
  14. [view removeFromSuperview];
  15. }
  16. }
  17. }

最近有个妹子弄的一个关于扩大眼界跟内含的订阅号,每天都会更新一些深度内容,在这里如果你感兴趣也可以关注一下(嘿对美女跟知识感兴趣),当然可以关注后输入:github 会有我的微信号,如果有问题你也可以在那找到我;当然不感兴趣无视此信息;

你真的了解UITableViewCell重用吗?的更多相关文章

  1. ios UITableViewCell重用问题

    在写sina 微博界面的过程中使用到了cell,那么就是在cell上添加一些控件,但是由于每条微博的内容都是不同的,所以在显示的过程中,出现了内容重叠的问题,其实就是UITableViewCell重用 ...

  2. 捉襟见肘之UITableViewCell重用引发的问题

    我记录一下自己如何解决cell内容重叠的问题 首先,复习一下:http://blog.csdn.net/omegayy/article/details/7356823 UITableViewCell的 ...

  3. UITableViewCell重用的问题

    UITableView中有两种重用Cell的方法: - (id)dequeueReusableCellWithIdentifier:(NSString *)identifier; - (id)dequ ...

  4. UITableViewCell重用机制

    UITableView是iOS开发中使用频率非常高的一个控件,它常被用来展示信息列表,尽管信息数据可能非常多,但UITableView消耗的资源却并不会随着展示信息的增多而变大,这都要得益于UITab ...

  5. 禁用UITableViewCell 重用机制

    有时候不想让Cell重用,怎么办勒.接下来介绍两种方法 方法一 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAt ...

  6. UITableviewCell 重用内存

    转载自:http://www.cnblogs.com/tangbinblog/p/3371545.html 重用实现分析 查看UITableView头文件,会找到NSMutableArray*  vi ...

  7. 有关UITableviewCell 重用内存 内部解析

    重用实现分析 查看UITableView头文件,会找到NSMutableArray*  visiableCells,和NSMutableDictnery* reusableTableCells两个结构 ...

  8. UITableViewCell重用导致内容混乱方案

    UITableViewCell *cell=nil; static NSString *reuse=@"cell"; if (cell==nil) { cell=[[UITable ...

  9. iOS解决cell重用问题

    在写sina 微博界面的过程中使用到了cell,那么就是在cell上添加一些控件,但是由于每条微博的内容都是不同的,所以在显示的过程中,出现了内容重叠的问题,其实就是UITableViewCell重用 ...

随机推荐

  1. [Offer收割]编程练习赛3 - 题目3 : 智力竞赛

    智力竞赛 Problem's Link ---------------------------------------------------------------------------- Mea ...

  2. VMware安装Elementary OS 后不能上网问题解决方法

    具体情况:之前在学校是通过有线网上网,VMware中的系统打开就可以直接连上网,现在回家图方便是通过无线路由器上网,发现虚拟机系统上不来网. 解决方法:控制面板->网络和Internet-> ...

  3. LINQ to SQL语句(3)之Count/Sum/Min/Max/Avg

    适用场景:统计数据吧,比如统计一些数据的个数,求和,最小值,最大值,平均数. Count 说明:返回集合中的元素个数,返回INT类型:不延迟.生成SQL语句为:SELECT COUNT(*) FROM ...

  4. ASP.NET伪静态的方法及相关资料

    1. 添加URLRewriter.dll引用 2. 配置web.config的基本信息 <configSections> <section name="RewriterCo ...

  5. [Asp.net 5] Configuration-新一代的配置文件(神奇的Binder)

    关于配置文件的目录:[Asp.net 5] Configuration-新一代的配置文件 之前看过MVC4.0的源码,里面就有Binder.作用是将前台页面传递过来的键值对/字典表绑定到特定的对象.此 ...

  6. 基于<MediaElement>的WPF视频播放器(带部分特效)【2】

    一.前言       上回说到需要做放视频的使用向导,这两天公司里的老司机一直帮我答疑解惑,让这个任务变得挺顺的,真心感谢他们! 这次与[1]中的不同之处在于: (1)播放和暂停按钮集成在<Me ...

  7. java实现可有括号的android计算器

    写了一个android版的计算器,可以计算带括号的表达式,不过前提是:正确的表达式才行 小缺陷是没有做表达式括号的控制,现在还没有想到好的控制方式 package javaAdvanced; impo ...

  8. jquery可见性选择器(综合)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. php实现中文字符串截取各种问题

    用php截取中文字符串会出现各种问题,做一简单汇总,文中的问题暂时还未解决,有大神解决了问题欢迎指教 <?php header('Content-Type:text/html;charset=u ...

  10. socket.io,远程控制你的幻灯片

    原文:http://www.cnblogs.com/xiezhengcai/p/3964455.html 中秋休息了几天,今天又开始捣鼓socket.io了.今天的任务是通过socket.io控制你的 ...