0

我在使用动态值时遇到了一些性能问题heightForRowAtIndexPath: (我知道这是这种方法,因为如果我设置静态值,响应能力会大大提高)。我的表格包含大约 3000 个单元格。

我理解为什么使用动态值时性能会受到影响(主要是因为方法中的计算必须对表中的每个单元格执行一次才能显示数据),但我不知道如何使其更有效.

在我遇到的许多类似问题中,建议的解决方案是使用NSString'sizeWithFont方法heightForRowAtIndexPath:来加快速度。我目前这样做,但表仍然需要大约 1.5 秒来加载(并重新加载,这有点频繁)。这太长了,我需要优化它。

我目前正在使用的代码(至少它的本质)如下:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell;
    UILabel *label = nil;

    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

        label = [[UILabel alloc] initWithFrame:CGRectZero];
        // set up label..
        [[cell contentView] addSubview:label];

    }

    NSDictionary *dict = alphabetDict; //dictionary of alphabet letters (A-Z). each key contains an NSArray as its object
    CGFloat rightMargin = 50.f; //padding for the tableview's index titles

    NSString *key = [[[dict allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)] objectAtIndex:indexPath.section];
    NSArray *array = [dict objectForKey:key];
    NSString *cellText = [array objectAtIndex:indexPath.row];

    //TABLE_WIDTH is 268.f, CELL_MARGIN is 14.f
    CGSize constraintSize = CGSizeMake(TABLE_WIDTH - (CELL_MARGIN * 2) - rightMargin, 20000.0f);
    CGSize labelSize = [cellText sizeWithFont:[UIFont systemFontOfSize:17] constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
    [label setFrame:CGRectMake(CELL_MARGIN, CELL_MARGIN, TABLE_WIDTH - (CELL_MARGIN * 2) - rightMargin, labelSize.height)];
    [label setText:cellText];

    return cell;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    //TODO make this faster

    NSDictionary *dict = alphabetDict;
    CGFloat rightMargin = 50.f;

    NSString *key = [[[dict allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)] objectAtIndex:indexPath.section];
    NSArray *array = [dict objectForKey:key];
    NSString *cellText = [array objectAtIndex:indexPath.row];

    CGSize constraintSize = CGSizeMake(TABLE_WIDTH - (CELL_MARGIN * 2) - rightMargin, 20000.0f);
    CGSize labelSize = [cellText sizeWithFont:[UIFont systemFontOfSize:17] constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];

    return labelSize.height + (CELL_MARGIN * 2) + 16.f;  
}

有人可以指出我正确的方向以进一步简化此代码吗?谢谢!

4

3 回答 3

5

我以前也遇到过类似的情况。我的解决方案是在执行 [tableView reloadData] 之前进行所有计算并将高度存储在名为 heightsArray 的 NSMutableArray 中。然后

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
   [heightsArray objectAtIndex:indexpath.row];
}

上下滚动时不计算。从数组中读取。由于预先进行了计算,最初的延迟会更多,但就滚动时的性能提升而言,这是值得的。您还可以在后台线程上执行计算,从而节省处理时间。只需在您可以在后台线程上调用并准备您的高度数组的方法中完成所有这些操作。

于 2012-08-27T18:07:56.543 回答
1

最耗时的部分heightForRowAtIndexPath是:

[[[dict allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)] objectAtIndex:indexPath.section];

因此,您可以从添加一个属性开始sortedKeys并像这样使用它:

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *key = [sortedKeys objectAtIndex:indexPath.section];
    CGFloat rightMargin = 50.f;
    // ...
}
于 2012-08-27T16:24:48.393 回答
0

crypticcoder 有一个很好的建议。我会建议一种变体,它可能更灵活,并支持表更改(插入、删除、重新排序)。

创建一个作为 UITableViewCell 子类的类,并向其添加 cellHeight 属性和 ivar cellHeight_。以这种方式合成它:

@synthesize cellHeight=cellHeight_;

使用类中的以下代码以惰性方式计算单元格高度:

-(CGFloat) cellHeight{
    if (cellHeight_ != 0)
        return cellHeight_;
    else {
        NSDictionary *dict = alphabetDict;
        CGFloat rightMargin = 50.f;

        NSString *key = [[[dict allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)] objectAtIndex:indexPath.section];
        NSArray *array = [dict objectForKey:key];
        NSString *cellText = [array objectAtIndex:indexPath.row];

        CGSize constraintSize = CGSizeMake(TABLE_WIDTH - (CELL_MARGIN * 2) - rightMargin, 20000.0f);
        CGSize labelSize = [cellText sizeWithFont:[UIFont systemFontOfSize:17] constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];

        cellHeight_ = labelSize.height + (CELL_MARGIN * 2) + 16.f; 
        return cellHeight_; 
    }
}

像 sch 一样,我不喜欢那里的那种,但如果这不是真正的性能问题,我就把它留在那里。

如果要更改单元格的内容,请确保将 cellHeight_ 重置为零,以便延迟重新计算(再次需要时)。

于 2012-08-27T18:31:02.273 回答