iOS 8桌面视图控制器性能问题
更新到iOS 8后,我的应用程序在UITableView中滚动时出现严重的性能问题 - 它在iOS 7上完全没有。它似乎滞后或经常跳转一点。iOS 8桌面视图控制器性能问题
它会影响较旧的(第二代)和较新的(第四代视网膜)iPad,但不会影响iPhone,因为我的iPhone 5可以通过以完全相同方式构建的TableView滚动。
重要:它似乎只影响UITableViewControllers在形式片呈现模态 - 在默认UIViewController中手动创建别的地方不表意见。甚至没有一个具有自定义表视图的UIViewController表单(例如属性)受到影响。
仪器说CPU时间大约3%转到cellForRowAtIndex方法,这是最耗时的方法。这3%中,75%呈上行:
EventTableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
cellForRowAtIndex看起来是这样的:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"tablecell";
EventTableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
NSDictionary *thismsg = [messages objectAtIndex:indexPath.row];
switch ([[thismsg objectForKey:@"type"] intValue]) {
case 1:
cell.eventTitleLabel.textColor = [UIColor greenColor];
break;
case 2:
cell.eventTitleLabel.textColor = [UIColor redColor];
break;
case 3:
cell.eventTitleLabel.textColor = [UIColor colorWithRed:0.0 green:128.0/255.0 blue:1.0 alpha:1];
break;
case 4:
cell.eventTitleLabel.textColor = [UIColor orangeColor];
break;
default:
cell.eventTitleLabel.textColor = [UIColor whiteColor];
break;
}
cell.eventTitleLabel.text = [thismsg objectForKey:@"m"];
cell.timestampLabel.text = [thismsg objectForKey:@"t"];
cell.authorNameLabel.text = [thismsg objectForKey:@"a"];
cell.backgroundColor = [UIColor blackColor]; // this needs to be here, but removing it makes no difference to performance.
return cell;
}
我的子类的细胞具有IB仅由几个标签,这是那些文字是分配给。
的视图控制器和表视图的故事板的设置是这样的:
EventTableViewCell.h:
属性链接到上述图像显示故事板的元件
@interface EventTableViewCell : UITableViewCell
@property (weak, nonatomic) IBOutlet UILabel *eventTitleLabel;
@property (weak, nonatomic) IBOutlet UILabel *timestampLabel;
@property (weak, nonatomic) IBOutlet UILabel *authorNameLabel;
@end
EventTableViewCell .m:
@implementation EventTableViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)awakeFromNib
{
// commenting out this method does nothing to performance, only makes it the wrong color
UIView *bgColorView = [[UIView alloc] init];
bgColorView.backgroundColor = [UIColor darkGrayColor];
[self setSelectedBackgroundView:bgColorView];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
@end
快速查看调试导航器在极端向上和向下滚动期间(您作为普通用户所做的任何事情都是如此)。正常的快速滚动会导致大约15%的CPU使用率。这些峰值在25%的标记 - 我假设,因为他们运行在同一线程和iPad有4可用。快速滚动的性能与慢速滚动的性能相同,因此CPU似乎并未参与其是否滞后。这个0%是在我停止滚动截取屏幕截图之后,表明该应用程序是而不是忙于在后台或其他视图控制器中执行其他任何操作。而且正如你所看到的,它也不会泄漏内存,因为无论持续滚动多长时间,它都会持续下降到23MB左右。
编辑:这一直在iOS 10中修复。我不知道原因是什么,但更新设备到iOS 10的结果与iOS7相同 - 平滑滚动如预期。 编辑再次:此问题已返回10.1或10.2。仍然不知道发生了什么事。
好的。经过数小时和数小时的分解我的应用程序,我发现原因。
事实证明,问题是由显示视图控制器而不是表视图控制器本身造成的。
以下是我发现了,且症状如何连接:
它不仅影响本地表视图控制器,因为这些都是由同一个问题的VC呈现。所有其他表格视图在其他地方或在有问题的VC中呈现,由于某种原因,这些视图没问题。
它与cellForRow方法或用于呈现每个单元格的类无关。
呈现视图控制器是一个全屏幕iPad视图控制器与很多按钮。这些按钮分别代表房间中的一个物体,可以挖掘物业。这一直工作正常,直到iOS 8,这个线程开始。由于我不知道的原因,按钮的0.7的alpha值使得任何呈现的Table View控制器的行为都不正确。我通过为呈现视图控制器逐个挑选元素而发现。
我禁用了我的按钮设置α,和一切工作的预期,因为它没有在iOS 7
我试图与iOS 8谷歌的α相关的问题,但一无所获行。
无论如何 - 问题解决了,尽管限制了我的按钮不再透明。
即时反馈:
注册笔尖和使用dequeueReusableCellWithIdentifier:forIndexPath:
。当你获取你的单元格时,你给表格视图提供了更多信息,因此大大增加了良好缓存的机会。您也可以放弃您的if (cell == nil)
条款。
这一点可能是最昂贵的部分:
UIView *bgColorView = [[UIView alloc] init];
bgColorView.backgroundColor = [UIColor darkGrayColor];
[cell setSelectedBackgroundView:bgColorView];
每一个观点是支持层和每一层都有GPU足迹。所以你在CPU和GPU方面都会导致分配。 tableview的视图重用的重点在于创建视图是昂贵的。
要解决这个问题,如果你去NIB路线,或者至少只做一次,可能在EventTableViewCell -initWithStyle:
之内。
相反,如果你想坚持使用纯代码的方法,下面应该工作:
// e.g. in viewDidLoad, assuming you have self.tableView; this tells the
// tableview that the class EventTableViewCell is the thing that is used to
// display any data with which you'd supply the reuse
// identifier CellIdentifier
[self.tableView registerClass:[EventTableViewCell class]
forCellReuseIdentifier:CellIdentifier];
... elsewhere ...
-(UITableViewCell *)
tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
EventTableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
// cell now definitely exists and is non-nil if EventTableViewCell
// is currently returning non-nil objects for
// initWithStyle:reuseIdentifier:; there's definitely no point calling
// that again, at least
NSDictionary *thismsg = [messages objectAtIndex:indexPath.row];
... etc ...
当然,这些都只是我的直接反应。如果你还没有运行Instruments,你甚至不知道瓶颈是否在你的tableview数据源中。只是把我的头顶部,它只是为可能EventTableViewCell
可以做一些昂贵的东西,那别人可能会增加额外的手势识别器,做自己的大处理任务等
注释掉整个块没有任何区别。我不明白第一部分?你不能删除if零部分,因为整个想法是检查单元是否已经静态创建。这是所有表视图的默认值,并且是在您创建UITableViewController的新子类时Xcode自动生成的代码。 – nickdnk 2014-09-22 18:48:06
@nickdnk你在谈论iOS 5及以下版本。检查文档。我引用:“在出列任何单元之前,调用此方法或registerNib:forCellReuseIdentifier:方法来告诉表视图如何创建新单元。如果指定类型的单元当前不在重用队列中,则表**视图使用提供的信息自动创建一个新的单元格对象**“(强调添加)(哦,如果你喜欢,可以注册一个类而不是NIB; NIB更容易,因为你可以直接将它们包含在Storyboard中,如果你在那里保持更新) – Tommy 2014-09-22 18:55:41
好吧。你能发布一个完整的例子吗?我真的不知道什么是笔尖。我只用过故事板,只是将我的TableViews,单元格等子类化了。编辑:我的意思是说出整个背景UIView - 添加没有任何区别。 – nickdnk 2014-09-22 19:36:11
你有没有尝试分析应用程序? – Shai 2014-09-22 06:47:04
你能否粘贴你的表格视图的代码 – meim 2014-09-22 07:08:11
@nickdnk如果你想成为一名认真的iOS开发人员学习使用Instruments。过去几年中,我不得不优化许多表格视图代码。人们可以犯的错误太多了。仪器可以帮助你做到更多。 – dasdom 2014-09-22 09:47:18