Objective c 动态高度为ROWATINDEXPATH:具有许多(数千)个单元格

Objective c 动态高度为ROWATINDEXPATH:具有许多(数千)个单元格,objective-c,uitableview,Objective C,Uitableview,在heightforrowatinexpath: (我知道这是一种方法,因为如果我设置一个静态值,响应性会显著提高)。我的桌子上有大约3000个电池 我理解为什么在使用动态值时性能会受到影响(主要是因为该方法中的计算必须对表中的每个单元格执行一次,然后才能显示数据),但我不知道如何提高效率 在我遇到的许多类似问题中,建议的解决方案是使用NSString的sizeWithFont方法在heightsforrowatinexpath:中加快速度。我现在这样做了,但是加载表仍然需要大约1.5秒的时间(

heightforrowatinexpath:
(我知道这是一种方法,因为如果我设置一个静态值,响应性会显著提高)。我的桌子上有大约3000个电池

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

在我遇到的许多类似问题中,建议的解决方案是使用
NSString
sizeWithFont
方法在
heightsforrowatinexpath:
中加快速度。我现在这样做了,但是加载表仍然需要大约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;  
}

有人能告诉我正确的方向来进一步简化代码吗?谢谢

heightforrowatinexpath
中,最耗时的部分是:

[[[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;
    // ...
}

heightforrowtaindexpath
中最耗时的部分是:

[[[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;
    // ...
}

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

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

上下滚动时没有计算。从数组中进行普通读取。最初的延迟会更多,因为计算是预先完成的,但在滚动时的性能提升方面是值得的。还可以在后台线程上执行计算,从而节省处理时间。只需在一个可以在后台线程上调用并准备heights数组的方法中完成所有这些

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

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

上下滚动时没有计算。从数组中进行普通读取。最初的延迟会更多,因为计算是预先完成的,但在滚动时的性能提升方面是值得的。还可以在后台线程上执行计算,从而节省处理时间。只需在一个可以在后台线程上调用并准备heights数组的方法中完成所有这些

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_uuu重置为零,以便延迟重新计算(再次需要时)。

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_uuu重置为零,以便在需要时延迟重新计算。

感谢您的建议-我实施了更改,它似乎缩短了几毫秒,但加载时间仍然不是我想要的。还有其他建议吗?我不可能让它尽可能的高效?谢谢你的建议-我实现了这个更改,它似乎缩短了几毫秒,但加载时间仍然不是我想要的。还有其他建议吗?我不可能使它尽可能的高效?你懒惰地计算是什么意思。这是否意味着在滚动时、在后台线程或新生成的线程上?延迟计算意味着直到需要结果时才进行计算。这是一种很好的方法,可以避免在一个时间段内进行大量配置,但在需要时分散计算。(如果一次需要它们,那么它不会更好,也不会更糟。)一旦计算出来,它就会被保存,在本例中,作为类中的ivar。在我的示例中,vlaue为零表示尚未计算该值。(我认为假设没有单元格高度为零是安全的。)我在if语句中犯了一个错误。我会纠正的。(如果(cellHeight!=0),则应为
。我还获得了cellheight的返回语句。我也添加了该语句。如果这造成了任何混乱,我很抱歉。你所说的懒惰计算是什么意思。它是指在滚动时、在后台线程上还是在新生成的线程上?懒惰计算意味着直到需要结果时才进行计算。这是避免ha的一个好方法避免在一个时间段内进行大量配置,但将计算分散到需要时进行(如果同时需要所有配置,则不会更好,也不会更糟)在本例中,它被保存为类中的ivar。在我的示例中,vlaue为零表示该值尚未计算。(我认为这是安全的。)