我有一个UITableView,在200个部分中有大约400个单元格,它在响应用户交互(滚动,选择单元格)方面有点迟钝。我已经确保检索单元格和标题视图的方法尽可能少,因为它是跑步,我不认为我做任何与众不同的事情让它变得缓慢。单元格和标题只有一个背景图像和文本。有没有其他人遇到过这种问题,你知道如何让它运行得更快一点吗?
编辑:我正在提供赏金,因为我很想得到一些有用的反馈。我不认为答案在于我的代码中的问题。相反,我正在寻找重新设计UITableView的策略,以便它运行得更快。我完全愿意添加新代码,我期待听到你们要说的话。
在模拟器和我的设备(iPhone 4)上都观察到了低迷。这是我viewForHeaderInSection
和cellForRowAtIndexPath
的实现,这是唯一实现非凡的UITableViewDelegate
方法。我正在重复使用单元格和标题视图。
- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger) section
{
HaikuHeaderView* view= [m_sectionViews objectAtIndex:section];
NSMutableArray* array= [m_haikuSearch objectAtIndex:section];
Haiku* haiku= [array objectAtIndex:0];
[view.poetLabel setText:[haiku nameForDisplay]];
return view;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
cell.backgroundView= [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cell gradient2.png"]];
// (Set up a bunch of label attributes in the cell...)
}
NSMutableArray* array= [m_haikuSearch objectAtIndex:indexPath.section];
Haiku* haiku = [array objectAtIndex:indexPath.row];
cell.textLabel.text = [haiku.m_lines objectAtIndex:0];
return cell;
}
答案 0 :(得分:48)
即使您的单元格实际上非常简单(背景图像和标签),也需要考虑一些事项
图片缓存 这是显而易见的事情 - 如果你在任何地方使用相同的图像,将它加载到UIImage中并重复使用它。即使系统将自己缓存它,直接使用已经加载的系统也不应该受到伤害。
快速计算 另一个相当明显的事情 - 尽可能快地计算高度和内容。不要进行同步提取(网络调用,磁盘读取等)。
图片中的Alpha通道 绘图时的成本是透明度的。由于您的单元格背景背后没有任何内容,请确保在没有Alpha通道的情况下保存图像。这节省了大量的处理。
透明标签 对于背景视图顶部的标签也是如此,不幸的是,使其不透明可能会破坏单元格的外观 - 但这取决于图像。
自定义单元格
通常,子类化UITableViewCell
并自己实现drawRect:
比构建子视图层次结构更快。您可以使图像成为所有实例使用的类变量。在drawRect:
中,您可以在上面绘制图像和文字。
检查合成 模拟器有一个工具来突出显示由于透明度而渲染成本昂贵的部分(绿色正常,红色是alpha混合)。它可以在调试菜单中找到:“Color Blended Layers”
答案 1 :(得分:9)
如果您希望加快代码速度,那么您可以做的最好的事情就是对其进行分析。这有两个原因:
你可以阅读一些可以提高表性能的方法,例如使用固定高度的单元格和重新使用单元格,它可能有助于实现这些东西(看起来你已经完成了)。但是当谈到加速你的代码时,你真的需要知道你的应用程序花费大部分时间在哪里。可能有一些方法需要很长时间,或者方法相对较快但被调用的次数比预期的要多得多。
除非你有一些数字需要衡量,否则我们无法知道你为加快速度而做出的改变是否真的有所作为。如果您可以证明您的代码在一个例行程序中花费了80%的时间并且将其降低到35%,那么您就知道自己正在取得进展。
因此,打破仪器并开始测量。如果可以,最好在进行每项不同的活动时进行测量,以便加速...在滚动时进行一次性能分析,一次在固定时间内选择尽可能多的不同单元格等等。别忘了保存结果,以便以后进行比较。
答案 2 :(得分:5)
请注意以下几点......
有关细胞重用的一些好信息是here ..
编辑:发现这个页面很晚..
这个SO question主题可能对你有帮助......特别是接受的答案......
答案 3 :(得分:3)
使用共享图像实例作为背景(每次创建新单元时都为每个文件分配/初始化/释放一个)。当您的表视图很大时,这意味着内存中的背景X单元占用的内存比它应该多得多。
而不是
cell.backgroundView= [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cell gradient2.png"]];
只需使用:
cell.backgroundView= [SomeHelperClass sharedBackgroundUIImageResource];
如果这没有帮助,请使用CG而不是标签和其他子视图(截图在这里有帮助......知道我们在说什么)。
答案 4 :(得分:2)
表视图的委托实现:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
如果是这样,您可能希望考虑设置UITableViewCell的rowHeight属性。
答案 5 :(得分:1)
您使用了很多子视图吗?
如果是这样,一个好的技巧是,而不是添加大量的标签和图像,使用CoreGraphics绘制它们。
为此,您必须继承UITableViewCell并实现-(void)drawRect:(CGRect)rect
方法。
答案 6 :(得分:1)
两个建议:一个是使用-initWithStyle:reuseIdentifier:
表示查看单元格而不是-initWithFrame:。另一种是注释掉将cell.backgroundView设置为带有渐变的图像,看看是否是罪魁祸首。每当我在桌面视图中表现不佳时,都是因为图像。
答案 7 :(得分:0)
这里有点偏离主题(因为所有单元格只有一个背景图像):
我的应用在每个单元格中显示不同的图像。向UITableView添加约5个单元格后,表格大幅减速。每次打开视图控制器时,处理所有图像大约需要1-2秒。
if let image = UIImage(contentsOfFile: photoFile){
// just set it and let system fit it
//cell.imageView!.image = image
// 1 - Calculate sized
let DEFAULT_THUMBNAIL_WIDTH: CGFloat = (cellHeight / 4) * 5;
let DEFAULT_THUMBNAIL_HEIGHT: CGFloat = cellHeight;
let aspectRatio: CGFloat = image.size.width / image.size.height
var willBeHeight = DEFAULT_THUMBNAIL_HEIGHT
var willBeWidth = DEFAULT_THUMBNAIL_HEIGHT * aspectRatio
if(willBeWidth > DEFAULT_THUMBNAIL_WIDTH){
willBeWidth = DEFAULT_THUMBNAIL_WIDTH
willBeHeight = willBeWidth / aspectRatio
}
let eps:CGFloat = 0.000001
assert((willBeHeight - eps) <= DEFAULT_THUMBNAIL_HEIGHT);
assert((willBeWidth - eps) <= DEFAULT_THUMBNAIL_WIDTH);
// 2 - Create context
var size:CGSize = CGSize(
width: DEFAULT_THUMBNAIL_WIDTH,
height: DEFAULT_THUMBNAIL_HEIGHT)
UIGraphicsBeginImageContext(size)
// one-to-one rect
//var imageRect: CGRect = CGRectMake(0.0, 0.0, size.width, size.height)
var imageRect: CGRect = CGRectMake(0.0, 0.0, willBeWidth, willBeHeight)
// 3 - Draw image
image.drawInRect(imageRect)
var imageResult: UIImage = UIGraphicsGetImageFromCurrentImageContext()
cell.imageView!.image = imageResult
UIGraphicsEndImageContext()
}else{
DDLogError("Can not draw photo: \(photoFile)")
}
所以我最终为我的所有图像生成了小的缩略图。
答案 8 :(得分:-1)
重复使用细胞。对象分配具有性能成本,特别是如果分配必须在短时间内重复发生 - 例如,当用户滚动表视图时。如果重用单元而不是分配新单元,则可以极大地提高表视图性能。 避免重新播放内容。当重复使用具有自定义子视图的单元格时,每次表格视图请求单元格时都不要布置这些子视图。创建单元格时,布置子视图一次。 使用不透明的子视图。自定义表格视图单元格时,使单元格的子视图不透明,不透明。