在heightForRowAtIndexPath:
中使用动态值时遇到一些性能问题(我知道这是一种方法,因为如果我设置一个静态值,响应能力会大大提高)。我的表包含大约3000个单元格。
我理解为什么在使用动态值时性能会受到影响(主要是因为在显示数据之前,必须对表中的每个单元格执行一次方法中的计算),但我不知道如何提高它的效率。
在我遇到的许多类似问题中,提出的解决方案是在heightForRowAtIndexPath:
中使用NSString
的sizeWithFont
方法来加快速度。我目前是这样做的,但该表仍然需要大约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;
}
有人能为我指明正确的方向来进一步简化这个代码吗?谢谢
我以前也遇到过类似的情况。我的解决方案是在进行[tableView reloadData]之前,先进行所有计算,并将高度存储在名为heightsArray的NSMutableArray中。然后
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
[heightsArray objectAtIndex:indexpath.row];
}
上下滚动时无计算。从数组中读取。最初的滞留将更多,因为计算是提前完成的,但就滚动时的性能提升而言,这是值得的。您还可以在后台线程上执行计算,从而节省处理时间。只需在一个方法中完成所有这些,您可以在后台线程上调用该方法并准备您的高度数组。
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;
// ...
}
crypticker有一个很好的建议。我建议使用一种更灵活的变体,并支持表更改(插入、删除、重新排序)。
创建一个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_重置为零,以便延迟重新计算(当再次需要时)。