iOS UITableViewCell 中的 Masonry 非常慢
Masonry in iOS UITableViewCell is very slow
我正在为 iPhone 开发一个 iOS 应用程序,并且有一个 UITableView,其中包含高度可变的自定义单元格。对于单元格的布局,我使用的是 Masonry: https://github.com/Masonry/Masonry。一切都按照我的喜好呈现,我唯一的问题是当一个新的单元格出现在屏幕上时会有一些滞后,足以严重阻碍用户体验。我对执行时间做了一些测试,似乎大部分延迟都在函数内部:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
执行时间大约是 iPhone 的十分之一秒 5. 此外,我发现大部分时间发生在函数中:
-(void)updateConstraints;
我的自定义 UITableViewCell class。在这个函数中,我使用 Masonry 在单元格中设置了各种视图约束。所以我基本上已经将这种延迟缩小到 Masonry 调用。如果您想知道,整个函数如下所示:
-(void)updateConstraints
{
[super updateConstraints];
[self.thumbnailImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.contentView.mas_top).offset(5);
make.left.equalTo(self.contentView.mas_left).offset(5);
make.right.equalTo(self.contentView.mas_right).offset(-5);
make.height.equalTo(@(self.thumbnailImageView.frame.size.width)).with.priorityHigh();
}];
[self.likeButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.thumbnailImageView.mas_bottom).offset(5);
make.left.equalTo(self.captionTextView.mas_right);
}];
[self.dislikeButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.thumbnailImageView.mas_bottom).offset(5);
make.left.equalTo(self.likeButton.mas_right);
make.right.equalTo(self.contentView.mas_right).offset(5);
}];
[self.captionTextView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.thumbnailImageView.mas_bottom).offset(5);
make.left.equalTo(self.contentView.mas_left);
make.right.equalTo(self.likeButton.mas_left);
make.height.equalTo(@([self captionHeight]));
}];
[self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.greaterThanOrEqualTo(self.captionTextView.mas_bottom).offset(5).with.priorityHigh();
make.bottom.equalTo(self.contentView.mas_bottom);
make.left.equalTo(self.contentView.mas_left).offset(5);
}];
[self.scoreLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.captionTextView.mas_right);
make.top.equalTo(self.likeButton.mas_bottom);
make.right.equalTo(self.contentView.mas_right);
}];
[self.numCommentsLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.greaterThanOrEqualTo(self.scoreLabel.mas_top);
make.bottom.equalTo(self.contentView.mas_bottom);
make.right.equalTo(self.contentView.mas_right);
}];
}
我想知道是否有任何方法可以减少执行时间并消除这种明显的延迟。我为每个单元格设置的约束与每个单元格的约束完全相同,但有一些例外。这只是 AutoLayout 的问题还是我正在做的事情非常错误?总的来说,这只是一个糟糕的方法吗?
经过多方探索,我发现问题的根本原因是我的细胞没有被正确回收。我的 cellForRowAtIndexPath 函数最初看起来像这样:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *postTableIdentifier = @"PostTableCell";
PostTableViewCell *cell = (PostTableViewCell *)[tableView dequeueReusableCellWithIdentifier:postTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:postTableIdentifier owner:self options:nil];
cell = [nib objectAtIndex:0];
}
//rest of function...
}
这里的 tableView 查找 reuseIdentifier 为@"PostTableCell" 的单元格。但是,loadNibNamed: 函数没有设置单元格的 reuseIdentifier,因此 dequeReusableCellWithIdentifier: 找不到回收的单元格。我在这里找到了解决这个问题的好方法:How can I recycle UITableViewCell objects created from a XIB? 我会让它自己回答,
但我的新代码如下所示:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *postTableIdentifier = @"PostTableCell";
PostTableViewCell *cell = (PostTableViewCell *)[tableView dequeueReusableCellWithIdentifier:postTableIdentifier];
if (cell == nil)
{
//register nib once
[tableView registerNib:[UINib nibWithNibName:postTableIdentifier bundle:nil] forCellReuseIdentifier:postTableIdentifier];
cell = (PostTableViewCell *)[tableView dequeueReusableCellWithIdentifier:postTableIdentifier];
}
//rest of function...
}
我正在为 iPhone 开发一个 iOS 应用程序,并且有一个 UITableView,其中包含高度可变的自定义单元格。对于单元格的布局,我使用的是 Masonry: https://github.com/Masonry/Masonry。一切都按照我的喜好呈现,我唯一的问题是当一个新的单元格出现在屏幕上时会有一些滞后,足以严重阻碍用户体验。我对执行时间做了一些测试,似乎大部分延迟都在函数内部:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
执行时间大约是 iPhone 的十分之一秒 5. 此外,我发现大部分时间发生在函数中:
-(void)updateConstraints;
我的自定义 UITableViewCell class。在这个函数中,我使用 Masonry 在单元格中设置了各种视图约束。所以我基本上已经将这种延迟缩小到 Masonry 调用。如果您想知道,整个函数如下所示:
-(void)updateConstraints
{
[super updateConstraints];
[self.thumbnailImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.contentView.mas_top).offset(5);
make.left.equalTo(self.contentView.mas_left).offset(5);
make.right.equalTo(self.contentView.mas_right).offset(-5);
make.height.equalTo(@(self.thumbnailImageView.frame.size.width)).with.priorityHigh();
}];
[self.likeButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.thumbnailImageView.mas_bottom).offset(5);
make.left.equalTo(self.captionTextView.mas_right);
}];
[self.dislikeButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.thumbnailImageView.mas_bottom).offset(5);
make.left.equalTo(self.likeButton.mas_right);
make.right.equalTo(self.contentView.mas_right).offset(5);
}];
[self.captionTextView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.thumbnailImageView.mas_bottom).offset(5);
make.left.equalTo(self.contentView.mas_left);
make.right.equalTo(self.likeButton.mas_left);
make.height.equalTo(@([self captionHeight]));
}];
[self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.greaterThanOrEqualTo(self.captionTextView.mas_bottom).offset(5).with.priorityHigh();
make.bottom.equalTo(self.contentView.mas_bottom);
make.left.equalTo(self.contentView.mas_left).offset(5);
}];
[self.scoreLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.captionTextView.mas_right);
make.top.equalTo(self.likeButton.mas_bottom);
make.right.equalTo(self.contentView.mas_right);
}];
[self.numCommentsLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.greaterThanOrEqualTo(self.scoreLabel.mas_top);
make.bottom.equalTo(self.contentView.mas_bottom);
make.right.equalTo(self.contentView.mas_right);
}];
}
我想知道是否有任何方法可以减少执行时间并消除这种明显的延迟。我为每个单元格设置的约束与每个单元格的约束完全相同,但有一些例外。这只是 AutoLayout 的问题还是我正在做的事情非常错误?总的来说,这只是一个糟糕的方法吗?
经过多方探索,我发现问题的根本原因是我的细胞没有被正确回收。我的 cellForRowAtIndexPath 函数最初看起来像这样:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *postTableIdentifier = @"PostTableCell";
PostTableViewCell *cell = (PostTableViewCell *)[tableView dequeueReusableCellWithIdentifier:postTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:postTableIdentifier owner:self options:nil];
cell = [nib objectAtIndex:0];
}
//rest of function...
}
这里的 tableView 查找 reuseIdentifier 为@"PostTableCell" 的单元格。但是,loadNibNamed: 函数没有设置单元格的 reuseIdentifier,因此 dequeReusableCellWithIdentifier: 找不到回收的单元格。我在这里找到了解决这个问题的好方法:How can I recycle UITableViewCell objects created from a XIB? 我会让它自己回答, 但我的新代码如下所示:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *postTableIdentifier = @"PostTableCell";
PostTableViewCell *cell = (PostTableViewCell *)[tableView dequeueReusableCellWithIdentifier:postTableIdentifier];
if (cell == nil)
{
//register nib once
[tableView registerNib:[UINib nibWithNibName:postTableIdentifier bundle:nil] forCellReuseIdentifier:postTableIdentifier];
cell = (PostTableViewCell *)[tableView dequeueReusableCellWithIdentifier:postTableIdentifier];
}
//rest of function...
}