Ios UITableViewCell正在出列时重新绘制

Ios UITableViewCell正在出列时重新绘制,ios,objective-c,uitableview,uistoryboard,tableviewcell,Ios,Objective C,Uitableview,Uistoryboard,Tableviewcell,我的设置 我有一个UITableViewCell,它位于UITableViewController的主情节提要中。它使用从RESTAPI中提取的一些JSON数据填充,这些数据将使每个单元格的高度可变。有uiimageview,UILabels所有不同的高度和样式,想想Instagram吧 我的问题 当我滚动到第5或第6个单元格,然后返回,它们开始重画和重叠,所以文本会混合,行会重画,等等 我尝试过的 这似乎是一个常见的问题,所以我尝试了几个张贴的解决方案。看起来我的问题可能和其他人面临的问题是一

我的设置

我有一个
UITableViewCell
,它位于
UITableViewController
的主情节提要中。它使用从RESTAPI中提取的一些JSON数据填充,这些数据将使每个单元格的高度可变。有
uiimageview
UILabels
所有不同的高度和样式,想想Instagram吧

我的问题

当我滚动到第5或第6个单元格,然后返回,它们开始重画和重叠,所以文本会混合,行会重画,等等

我尝试过的

这似乎是一个常见的问题,所以我尝试了几个张贴的解决方案。看起来我的问题可能和其他人面临的问题是一样的,那就是,每次我的手机出列时,我都会在手机上调用
addSubview
,但我试着检查手机是否已经存在。我在某处看到另一篇帖子(对不起,我不记得在哪里),这篇帖子表明,因为我在故事板中创建了这个,它已经初始化,
if(!cell)
将返回false,所以我不知道如何防止它重绘

当我尝试从情节提要中删除单元格并以编程方式创建它时,我收到一个错误消息,说它找不到标识符为“cell”的单元格

我还尝试过某人的解决方案,在我出列时删除所有子视图,因此我使用:

for ( UIView *view in cell.contentView.subviews ) {
     if ([view isKindOfClass:[UIView class]]) {
         [view removeFromSuperview];
     }
}

它找不到任何东西。

尝试在cell类中添加一个新方法,将cell重置为其默认样式,并在
出列cell
@rdelmar的注释正确后调用此方法。你不应该做你正在做的事。也许有用,但这是一种坏习惯,你不想养成坏习惯

首先,利用面向对象编程。单元格应该能够根据您要求其显示的数据进行自我配置。表视图不应设计单元格

UITableViewCells需要针对速度进行优化。创建和添加子视图是一个缓慢的过程。可以只做一次,但是单元将被重用(系统优化),您应该重用第一次创建单元时添加的现有视图

例如,如果不需要子视图,可以隐藏它们。您可能希望在准备之前执行此操作。可以在布局子视图中移动它们。或者在-updateConstraint中更改子视图的位置


通常,您只需要将要显示的数据从数据源(通常是视图控制器)传递给表视图单元子类。让单元格完成显示工作。

当您在将您的单元格退出队列后添加子视图时,请为您的子视图添加一个标记。这样,当您将单元格出列时,可以首先使用标记检查是否存在子视图,如果存在子视图,请在添加新视图之前将其删除:

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    ...
    // try to dequeue a cell
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:<yourCellIdentifier>];

    if( !cell )
    {
        // create a new cell if necessary
    }

    static int _myViewTag = 1000987 // give it a high int : low value are used by the system in cells

    UIView *v = cell.contentView viewWithTag:_myViewTag];

    if( v ) // subview with such tag already exists, so remove it.
        [v removeFromSuperview];

    // now add your new subview
    [cell.contentView addSubview:<yourView>];

    // adjust height of cell to your view.
    ...
}
-(UITableViewCell*)表视图:(UITableView*)表视图
cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
...
//尝试将单元格出列
UITableViewCell*单元格=[tableView dequeueReusableCellWithIdentifier:];
如果(!单元格)
{
//如有必要,创建一个新单元
}
static int _myViewTag=1000987//给它一个高int值:系统在单元格中使用低值
UIView*v=cell.contentView视图带标记:_myViewTag];
如果(v)//具有该标记的子视图已经存在,那么将其删除。
[v从SuperView移除];
//现在添加新的子视图
[cell.contentView addSubview:];
//根据您的视图调整单元格的高度。
...
}

最有效的管理方法是将
UITableViewCell
子类化,并将所有必需的
视图添加为属性。因此,现在当一个细胞出现“回收”,你知道在哪里可以找到旧的看法,如:

[cell.myTextLabel setText:@""];
啊,你完了

更新如果只有少量“类型”单元格,则创建子类是有意义的。为每个类创建一个子类。它的复杂程度取决于您的具体场景。但我已经做到了,并且发现这是最有效的方法


更新2或者您可以在故事板中创建多个单元格,并根据数据源将相应的单元格出列,保存所有编码。

谢谢@britto thomas,您能详细说明一下吗?只需将单元格中所有子视图的框架设置为方法中的默认样式。或者,如果您的单元格有不同的样式,请在自定义单元格类中为单元格设计添加不同的方法,并在加载之前根据需要调用它。我遇到的问题之一是,当我尝试迭代子视图时,似乎什么都没有。请参阅我的原始文章的最后一部分,了解我试图运行的代码。最简单的解决方案是在故事板中创建所有子视图,这样就不必添加任何代码。如果要在代码中添加它们,请创建UITableViewCell子类,并在其init方法中添加子视图。在cellForRowAtIndexPath中添加子视图很少是最好的方法。谢谢@rdelmar。当我不知道那里肯定会有什么内容时,我该怎么做?我知道我会有一个图像和至少两个标签,但我可以有额外的标签或按钮。这就是您建议将其子类化的原因吗?如果您要基于indexPath添加这些额外的视图(有些行具有这些视图,有些不基于数据源),那么您确实需要将它们添加到cellForRow中。如果没有太多不同的单元格类型,另一种解决方案是在故事板中创建多个单元格,然后根据数据源将相应的单元格排出来。谢谢,我会在早上尝试一下,然后再给你回复。@rdelmar-我睡不着,不得不尝试一下,最后成功了。我相信这是可以改进的,但MVP是我现在需要的。“你能把这个贴出来作为答案吗?这样我就可以核对一下了。谢谢,”戴夫·巴顿说。你在这两件事上都是对的,勒马尔