自定义 UITableviewCell 放弃内存问题

Posted

技术标签:

【中文标题】自定义 UITableviewCell 放弃内存问题【英文标题】:Custom UITableviewCell abandon memory issue 【发布时间】:2014-07-10 06:47:58 【问题描述】:

目前我正在尝试使用来自仪器的数据优化我的 ios 应用程序。我注意到我的一个 UITableViewCell 存在问题,如果点击上面的单元格,我会插入或删除该单元格。问题是我的单元格似乎没有在 cellForRowAtIndexPath 中被回收,而是创建了一个全新的单元格,并且在此之前创建的单元格被丢弃并留在内存中。这导致了一个主要问题,因为每个单元的成本约为 2mb,因此很容易使用大量内存,并且只需轻按单元打开和关闭即可超过 100mb。如下图所示。

我的自定义 UITableViewCell 包含

UIScrollView 自定义UIView(图形视图) 自定义UIView(轴视图)

其他一些信息

使用带有UIScrollView 和其他控件的原型单元格(代码中未显示) GraphicView 子类 uiview 并使用 drawRect 绘制图形。

我不确定我是否使用了正确的方法,因为用户通常一次只会在屏幕上看到一个单元格。我的问题是我的代码有什么问题,为什么我使用了这么多内存,我该如何解决这个问题?

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

    if([self.prices[indexPath.row] isEqual:@(1)])
    
        static NSString *CellIdentifier = @"statCell";
        PTPriceStatCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

        int width = kOffsetX + dateRangeInDays * kStepX + kOffsetX;
        float axisWidth = //Some calculataion;

        cell.scrollView.frame = CGRectMake(0,0,cell.frame.size.width - axisWidth, 128);

       GraphView *graphView = [[GraphView alloc]initWithFrame:CGRectMake(axisWidth, 0, width , cell.scrollView.frame.size.height)];

        graphView.range = dateRangeInDays;
        graphView.xValues= xAxis;
        graphView.yValues = yAxis;
        graphView.earliestDate = earliestDate;


        [cell.scrollView addSubview:graphView];

        CGPoint bottomOffset = CGPointMake( cell.scrollView.contentSize.width - cell.scrollView.bounds.size.width,0);
        [cell.scrollView setContentOffset:bottomOffset animated:NO];
        YAxis *axisView = [[YAxis alloc]initWithFrame:CGRectMake(0, cell.scrollView.frame.origin.y, axisWidth, cell.scrollView.frame.size.height)];

        axisView.yValues = yAxis;
        [cell.contentView addSubview:axisView];
        cell.scrollView.contentSize = CGSizeMake(cell.scrollView.graphView.frame.size.width + axisWidth, cell.scrollView.graphView.frame.size.height);

        return cell;
    



- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath     *)indexPath

    if (range < [self.prices count] && [[self.prices objectAtIndex:range] isEqual:@(1)])
    
          [self.prices removeObjectAtIndex:range];
          [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; 
     
     else
     
         Price *currentPrice = self.prices[[self getPricePositionFor:(int)indexPath.row]][0];
         if (currentPrice.value != nil) 
         
             [self.prices insertObject:@(1) atIndex:range];
             [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
         
     

【问题讨论】:

如果(...)这个条件是什么?我认为您没有在问题中发布正确的代码。 您正在重复使用您的单元格。但问题在于您的“graphView”和“axisView”。检查单元格中是否存在这些视图,然后跳过该部分代码。希望它会有所帮助。 【参考方案1】:

您正在使可重复使用的单元格出列,但请继续向它们添加 graphViewsaxisViews。由于它们从未从单元格中删除,因此它们正在加起来。

如果您 a) 检查单元格上是否已经存在这些视图并重新配置它们,或者 b) 在 PTPriceStatCell 上实现 -prepareForReuse 并在那里清理单元格的子视图,问题应该会消失。

最小的清理示例:

NSArray *oldGraphs = [cell.scrollView.subviews filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id subview, NSDictionary *bindings) 
    return [subview isKindOfClass:[GraphView class]];
]];
[oldGraphs makeObjectsPerformSelector:@selector(removeFromSuperview)];

【讨论】:

非常感谢,这个解决方案奏效了!我不知道这种方法存在。我很感激,昨晚我一直到凌晨 4 点才试图找到没有结果的解决方案。我现在终于可以发布应用程序并获得一些急需的睡眠。再次感谢您。【参考方案2】:

只要让 GraphView 和 AxisView 作为 PTPriceStatCell 的属性。并使用 cell.graphView 或 cell.axisView 访问。您的代码每次都在实例化它们并且永远不会释放它。

【讨论】:

我之前尝试过这个解决方案,但没有解决问题。不过感谢您的回答。

以上是关于自定义 UITableviewCell 放弃内存问题的主要内容,如果未能解决你的问题,请参考以下文章

自定义 UITableViewCell 的自动布局约束在运行时失败

如何在uitableviewcell内绘制一个矩形

通过点击单元格内的图像从 UITableViewCell 中分离

旋转 UITableViewCell

UITableViewCell 内存问题中的异步图像加载

缺少返回 UITableViewCell