2

每当我滚动我的表格视图时,它都非常滞后。我认为这与我加载细胞的方式有关。我尽可能使用 UINib (5.0+),同时仍然提供向后兼容性。然后,我使用来自 NSArray 的 NSDictionary 中的项目加载自定义单元格的标签和图像,该 NSArray 是从 ViewDidLoad 中的 NSUserDefaults 加载的。

有什么办法可以提高这个 cellForRowAtIndexPath 的效率吗?

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

    CustomCell *cell = (CustomCell *)[aTableView dequeueReusableCellWithIdentifier:@"Cell"];
    if (cell == nil) {
        if ([self labelCellNib]) {
            [[self labelCellNib] instantiateWithOwner:self options:nil];
        } else {
            [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
        }
        cell = [self CustomTableCell];
        [self setCustomTableCell:nil];
    }
    NSDictionary *dictionary = [myArray objectAtIndex:indexPath.row];
    NSData *data = [dictionary objectForKey:@"OCRImage"];
    cell.previewPicture.image = [self roundCorneredImage:[UIImage imageWithData:data] radius:60];

    cell.titleLabel.text = [dictionary objectForKey:@"Title"];
    cell.titleLabel.delegate = self;

    cell.dateLabel.text = [dictionary objectForKey:@"Date"];

    if (indexPath.row%2) {
        cell.backgroundImage.image = firstImage;
    }
    else {
        cell.backgroundImage.image = secondImage;
    }
    return cell;
}

编辑:

- (UIImage*)roundCorneredImage: (UIImage*)orig radius:(CGFloat) r {
    UIGraphicsBeginImageContextWithOptions(orig.size, NO, 0);
    [[UIBezierPath bezierPathWithRoundedRect:(CGRect){CGPointZero, orig.size} 
                                cornerRadius:r] addClip];
    [orig drawInRect:(CGRect){CGPointZero, orig.size}];
    UIImage* result = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return result;
}

Edit2:这些是导致滞后的行:

NSData *data = [dictionary objectForKey:@"OCRImage"];
cell.previewPicture.image = [self roundCorneredImage:[UIImage imageWithData:data] radius:60];
4

3 回答 3

3

正如@Till 在评论中所说,您应该在 Instruments 中启动您的应用程序(Xcode 中的 Product -> Profile),然后选择 CPU -> Time Profiler 仪器。

然后,在该位置上滚动几秒钟,然后点击 Instruments 中的 Record 工具栏图标以关闭您的应用程序。您将能够看到滚动部分,因为 CPU 使用率可能会固定为 100%(除非它因为网络活动问题而变慢)。

点击CPU高活动区域开始后的时间线,点击“开始巡查范围”工具栏按钮,再点击高CPU活动区域结束前的“停止巡查范围”工具栏按钮。

您现在可以深入查看窗口底部的调用树视图,以准确了解您的所有 CPU 使用情况。根据我的经验,如果您关闭左侧的“反转调用树”选项,通常更容易找到问题。

性能错误可能很难找到,有时显然很慢的代码行实际上根本不会引起任何问题。在不浪费时间的情况下解决性能问题的唯一方法是使用 Instruments。

于 2012-01-01T20:39:19.903 回答
2

确保您已将单元格的重用标识符设置为您在代码中指定的相同内容,即@"Cell". 如果它们不匹配,那么您将无法正确重用单元格,并且可能会花费更多时间来创建单元格而不是必要的。

如果您正确回收单元格,那么您应该查看块之后的代码if (cell == nil) {...}。一旦表格创建了足够的单元格来填充屏幕(可能还有一两个),您将跳过整个块,因此滚动时归因于此方法的大部分时间将归因于以下代码。知道什么是有趣myArray的,如果它实际上是一个数组,该objectForKey:方法的作用是什么。没有其他东西看起来应该花费很长时间,但是找出周期去向的最好方法是在 Instruments 中分析你的代码。

于 2012-01-01T20:36:50.373 回答
1

查看您的代码后我的一些笔记:

  1. 是否roundCorneredImage:radius:缓存结果?如果不是这样,为每个单元执行 CG 调用肯定会出现瓶颈。更新:请确保使用工具,但将处理UIImage后的数据存储在集合中可能会更快(允许内存),以便您可以在下次使用相同参数调用该方法时再次将其拉出。

  2. 您的所有UIImages 都可以在其他地方声明,然后在此方法中呈现。您当前的代码UIImage为每个单元格实例化一个新单元格,这也可能成为您滚动的瓶颈。更新:由于Image1.pngImage2.png基本上是静态的,您可以在界面中声明它们或将它们声明为静态 ivar,然后将它们分配给背景图像,而不是UIImage每次都实例化。

  3. 子类化和实例化它可能会更快UITableViewCell,而不是进入UINib. 此外,您还可以将您的布局/数据逻辑与委托方法分开。这是我在子类中所做的要点UITableViewCell。基本上,我将实体与单元格一起存储,并且单元格知道它的标签等。这将单元格布局逻辑排除在我的数据源代码之外。

  4. 看起来您正在使用 anNSDictionary作为数据源。如果您在该字典中有很多对象,则使用它可能会更快,CoreData并且NSFetchedResultsController. 这是一个关于这个问题的好帖子更新:好的,这不应该是一个问题。

-

编辑

因此,如果您删除了所有这些:

NSDictionary *dictionary = [myArray objectForKey:@"OCRImage"];
cell.previewPicture.image = [self roundCorneredImage:[UIImage imageWithData:data] radius:60];

if (indexPath.row%2) {
    cell.backgroundImage.image = firstImage;
}
else {
    cell.backgroundImage.image = secondImage;
}

它仍然滞后,让我们看看你的构造函数......这些行做什么?

cell = [self CustomTableCell];
[self setCustomTableCell:nil];

另外,您没有在表格单元格中使用任何透明图像或任何东西是吗?众所周知,这些会导致绘图延迟...

-

编辑#2

如果你剥离到这一点,会发生什么?

CustomCell *cell = (CustomCell *)[aTableView dequeueReusableCellWithIdentifier:@"Cell"];
if (cell == nil) {
    if ([self labelCellNib]) {
        [[self labelCellNib] instantiateWithOwner:self options:nil];
    } else {
        [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
    }
    cell = [self CustomTableCell];
    [self setCustomTableCell:nil];
}

cell.titleLabel.text = [dictionary objectForKey:@"Title"];
于 2012-01-01T20:32:08.787 回答