自定义UITableViewCells不会在UITableView上重用

时间:2013-02-27 16:51:58

标签: iphone ios objective-c uitableview

似乎有很多问题,但我无法使用其他任何人的答案,所以希望有人可以回顾我是怎么做的。我正在尝试使用。我有两个自定义的UITableViewCells,它们现在只有一个BOOL属性,就像样式一样。

在我的cellForRowAtIndexPath方法中,根据回来的数据类型,我正在设计我的单元格样式。如果数据是"月"标题是一个看起来很瘦的细胞,如果它是一个"新闻项目"它将是一个更大的白色细胞。

enter image description here

当表加载一切看起来很棒但是如果我向下滚动以创建更多单元格然后向上滚动则正在重新创建单元格并最终滚动速度变慢,因为我的内存不足。

当我设置断点时,dequeueReusableCellWithIdentifier总是返回nil,所以我的单元格永远不会被重用,这似乎是一个问题。

在这张图片中,您可以看到细胞堆叠在一起并混乱:

enter image description here

这是我的代码:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *NewsCellIdentifer = @"NewsCellIdentifier";
    static NSString *MonthCellIdentifier = @"MonthCellIdentifier";


    NSUInteger row = [indexPath row];
    NewsItem *item = [self.newsArray objectAtIndex:row];

    if (item.IsMonth == YES)
    {
        NewsMonthUITableViewCell *cell = [self.mytableView dequeueReusableCellWithIdentifier:MonthCellIdentifier];

        if (cell == nil)
        {
            cell = [[NewsMonthUITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MonthCellIdentifier];
        }

        // This handles any other "date" cells to allow for different spacing styles.
        if (item.IsMonth)
        {
            UIImageView *av = [[UIImageView alloc] initWithFrame:CGRectMake(0, 10, 400, 20)];
            av.backgroundColor = [UIColor clearColor];
            av.opaque = NO;
            av.image = [UIImage imageNamed:@"month-bar-bkgd.png"];
            UILabel *monthTextLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 150, 20)];;
            CGFloat font = 11.0f;
            monthTextLabel.font = [BVFont HelveticaNeue:&font];
            monthTextLabel.backgroundColor = [UIColor clearColor];
            monthTextLabel.font = [BVFont HelveticaNeue:&font];
            monthTextLabel.textColor = [BVFont WebGrey];
            monthTextLabel.text = item.Title;

            cell.backgroundColor = [UIColor clearColor];
            [cell.contentView addSubview:av];
            [cell.contentView addSubview:monthTextLabel];
        }

        return cell;

    }
    else
    {
        NewsUITableViewCell *cell = [self.mytableView dequeueReusableCellWithIdentifier:NewsCellIdentifer];

        if (cell == nil)
        {
            cell = [[NewsUITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:NewsCellIdentifer];
        }

        cell.contentView.backgroundColor = [UIColor clearColor];

        UIView *whiteRoundedCornerView = [[UIView alloc] initWithFrame:CGRectMake(10,10,300,100)];
        whiteRoundedCornerView.backgroundColor = [UIColor whiteColor];
        whiteRoundedCornerView.layer.masksToBounds = NO;
        whiteRoundedCornerView.layer.cornerRadius = 3.0;
        whiteRoundedCornerView.layer.shadowOffset = CGSizeMake(-1, 1);
        whiteRoundedCornerView.layer.shadowOpacity = 0.5;

        [cell.contentView addSubview:whiteRoundedCornerView];
        [cell.contentView sendSubviewToBack:whiteRoundedCornerView];
        [cell.contentView addSubview:[self NewsItemThumbnailView:item]];
        [cell.contentView addSubview:[self NewsItemTextView:item]];
        [cell.contentView addSubview:[self NewsItemCornerIconIndicatorView:item]];

        return cell;

    }

    return nil;

}

感谢您的任何帮助或建议!

4 个答案:

答案 0 :(得分:2)

当您使用没有动态原型的Storyboard时,您需要放置代码,在if (cell==nil)块内创建并添加子视图。否则,每次重新使用tableview单元格时,都会再次添加所有子视图。

继续前进,我的建议是使用具有动态原型的故事板(具有子类UITableViewCells)并在IB中的单元格中进行自定义。

答案 1 :(得分:1)

将您的单元格转换为Customcells,并仅使用tableView,请参阅下面的示例。

   NewsMonthUITableViewCell *cell = (NewsMonthUITableViewCell *)[tableView dequeueReusableCellWithIdentifier:MonthCellIdentifier];
  NewsUITableViewCell *cell =(NewsUITableViewCell*) [tableView dequeueReusableCellWithIdentifier:NewsCellIdentifer];

使用动态原型单元,对于原型单元,不需要单元分配&检查正确的cellIdentifier。

故事板上的

创建两个原型单元&给他们不同的cellIdentifier,在你的情况下NewsCellIdentifer& MonthCellIdentifier。确保NewsCellIdentifer拼写错误,因为你错过了来自NewsCellIdentifer的i

答案 2 :(得分:1)

有趣的问题。你说你的细胞出列正在返回零。这是否已通过断点或日志确认?或者这仅仅是您发布的图像的推论?

在我看来,可能存在另一个罪魁祸首,即细胞堆叠在彼此之上并且没有被重复使用。

我可以看到每次滚动单元格时都会创建whiteRoundedCornerView并将其添加到单元格中。即使这不是你的问题的原因,它肯定是一个问题。您没有正确创建单元格。您必须将此代码放入if(cell == nil)块中。事实上,几乎所有位于块之外的代码都需要进入它。然后,任何设置文本或图像值的代码都应该在块之外。我看到有人已经提出这个建议,但它并没有让你满意。我再次强调它仍然是错误的,如果你想修复你的应用,你需要解决这个问题。 (顺便说一句漂​​亮的应用程序)。

另外,如果我可以对您的代码的其他方面提出建议。您自定义编码标题,并没有使用实际的节标题。这对我来说很奇怪。此外,你有一个冗余的“if(item.isMonth)”。由于一个已经在另一个的块中,它将始终是一个月项目。

答案 3 :(得分:0)

我在iOS 7和故事板上遇到了同样的问题,而我从来没有在老版Xcode-SDK版本上使用相同的代码出现此问题,并且尝试了很多来自stackoverflow的建议,我无法修复它,猜猜是什么?! Apple的TableView Programming Guide有很好的解释指南。 甚至不需要使用cell==nil

所以我把这些说明放在这里,希望能帮助别人:

要使用可以正确重复使用的故事板创建自定义tableview单元格,您可以采用两种不同的审批方式。我个人更喜欢第一个更直接的,但我把两个解决方案放在这里。

第一种方法

  1. 使用Master-Detail Application模板创建项目,然后选择Use Storyboards选项。
  2. 在情节提要画布上,选择主视图控制器。
  3. 在Identity检查器中,验证Class是否已设置为自定义MasterViewController类。
  4. 选择主视图控制器内的表格视图。
  5. 在“属性”检查器中,验证“内容”弹出菜单是否设置为“动态原型”。
  6. 选择原型单元格。
  7. 在“属性”检查器中,在“样式”弹出菜单中选择“自定义”。
  8. 在“标识符”文本字段中输入重用标识符。 这与您在dequeueReusableCellWithIdentifier:消息中发送到表视图的重用标识符相同。
  9. 在“附件”弹出菜单中选择“披露指示器”。
  10. 将对象从库中拖到单元格上。 对于此示例,拖动两个标签对象并将它们放置在单元格的末端附近(为附件视图留出空间)。
  11. 选择对象并设置其属性,大小和自动调整特征。
  12. 为此过程的编程部分设置的一个重要属性是每个对象的tag属性。在View的{​​{1}}部分中找到此属性,并为每个对象分配一个唯一的整数。

    现在编写您通常编写的代码以获取表视图的数据。 (对于此示例,您需要的唯一数据是每个单元格的行号。)实现数据源方法tableView:cellForRowAtIndexPath:从原型创建新单元格并使用数据填充它,方式类似于此代码:

    Attributes inspector

    此代码有几个方面需要注意:

    • 您分配给原型单元格的字符串标识符与传递给- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyIdentifier"]; UILabel *label; label = (UILabel *)[cell viewWithTag:1]; label.text = [NSString stringWithFormat:@"%d", indexPath.row]; label = (UILabel *)[cell viewWithTag:2]; label.text = [NSString stringWithFormat:@"%d", NUMBER_OF_ROWS - indexPath.row]; return cell; } 中的表格视图的字符串相同。
    • 由于原型单元格是在故事板中定义的,因此dequeueReusableCellWithIdentifier:方法始终返回有效的单元格。您无需针对nil检查返回值并手动创建单元格。
    • 代码通过调用dequeueReusableCellWithIdentifier:来获取单元格中的标签,并传入其标记整数。然后,它可以设置标签的文本内容。

    第二种方法

    如果您不想使用标签,可以使用其他方法在单元格中设置内容。使用要设置的对象的outlet属性定义自定义viewWithTag:子类。在故事板中,将新类与原型单元关联,并将出口连接到单元中的相应对象。

    使用自定义单元格内容的商店

    1. 将名为MyTableViewCell的Objective-C类添加到项目中。
    2. 将以下代码添加到UITableViewCell

      中的界面

      @interface MyTableViewCell:UITableViewCell

      @property(非原子,弱)IBOutlet UILabel * firstLabel; @property(非原子,弱)IBOutlet UILabel * secondLabel; @end

    3. 将以下代码添加到MyTableViewCell.h中的实现:

      @synthesize firstLabel,secondLabel;

    4. 将以下代码行添加到实现数据源的源文件中:

      #import“MyTableViewCell.h”

    5. 使用MyTableViewCell.m将原型单元格的类设置为Identity inspector

    6. 使用Connections检查器将原型单元格中的两个出口连接到相应的标签。 enter image description here

    7. 实施数据源方法MyTableViewCell

      tableView:cellForRowAtIndexPath:
    8. 代码使用访问器方法访问单元格中的标签(此处使用点表示法)。然后,代码可以设置标签的文本内容。