I am working on an iOS app for the iPhone and have a UITableView with custom cells that have variable height. For the layout of the cells I am using Masonry: https://github.com/Masonry/Masonry. Everything is rendering to my liking, the only problem I have is that there is some lag when a new cell comes onto the screen, enough to seriously hinder the user experience. I did some testing on execution time and it seems that the bulk of this lag is inside of the function:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
The execution time is on the order of a tenth of a second on iPhone 5. Further, I have found that most of this time happens in the function:
-(void)updateConstraints;
of my custom UITableViewCell class. In this function I set various constraints of views in the cell using Masonry. So I have essentially narrowed down this lag to Masonry calls. If you are wondering, the whole function looks like this:
-(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);
}];
}
What I am wondering is if there is any way to reduce the execution time and remove this noticeable lag. The constraints that I am setting for each cell are the exact same constraints for every cell, with a few exceptions. Is this just an issue with AutoLayout or is something very wrong to what I am doing? overall is this just a bad approach?
After more exploration, I found that the root cause of the problem was that my cells were not being properly recycled. My cellForRowAtIndexPath function originally looked like this:
Here the tableView looks for cells with a reuseIdentifier of @"PostTableCell". However, the loadNibNamed: function does not set the cell's reuseIdentifier, and so a dequeReusableCellWithIdentifier: could not find recycled cells. I found a good solution to this problem here: How can I recycle UITableViewCell objects created from a XIB? I will let it answer for itself, but my new code looks like this: