I have a UIViewController with a UITableView that is loading incredibly slow (slow as molasses, perhaps) I can tell it's due to setting custom background images for UITableViewCells in my grouped UITableview owned by the ViewController.
I think I'm following as much as the recommendation noted in this other SO question: Tricks for improving iPhone UITableView scrolling performance
I've also followed this article to make sure I'm not doing something stupid: Cocoa With Love Custom UITableView Drawing
As soon as I don't invoke background styling code, the performance improves.
Following the suggestions, I'm doing all these steps:
- Because of the way the designs are, I have 2 different cell variations and cannot have uniform row height. Regardless of the cell variation, the row background is always 1 of 3 images and is based on the row index. 0: top_row_image, n-1: bottom_row_image, all others: middle_row_image
- I'm loading the images used for the background in my ViewController's viewDidLoad.
- I don't have any drawRect code as I'm letting the UITextField inside the cell handle that
- Cell's layer is set to opaque
- Cell identifiers are being reused
- Not loading the cell from a NIB file
Basically, I want to style the each of the table's section's rows with different top, middle and bottom row background images, depending on which type of row type it is. Can anyone suggest a better way to have custom backgrounds on a UITableView?
Here's my code:
ViewController:
@property (nonatomic, weak) IBOutlet *tableview;
@property (nonatomic, strong, readwrite) UIImage *topRowImage;
@property (nonatomic, strong, readwrite) UIImage *middleRowImage;
@property (nonatomic, strong, readwrite) UIImage *bottomRowImage;
@synthesize tableview = _tableview;
@synthesize topRowImage = _topRowImage;
@synthesize middleRowImage = _middleRowImage;
@synthesize bottomRowImage = _bottomRowImage;
// Load the images that will be used for the cell background ahead of time
- (void)viewDidLoad
{
[super viewDidLoad];
// All of the images are 60x20 but my cells are 300x44 or 300x56
UIEdgeInsets edgeInsets = UIEdgeInsetsMake(2, 4, 2, 4);
self.topRowImage = [[UIImage imageNamed:@"top_row.png"] resizableImageWithCapInsets:edgeInsets];
UIEdgeInsets edgeInsets = UIEdgeInsetsMake(0, 4, 0, 4);
self.middleRowImage = [[UIImage imageNamed:@"middle_row.png"] resizableImageWithCapInsets:edgeInsets];
edgeInsets = UIEdgeInsetsMake(2, 4, 2, 4);
self.bottomRowImage = [[UIImage imageNamed:@"bottom_row.png"] resizableImageWithCapInsets:edgeInsets];
}
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellId = [self getCellIdAt:indexPath];
BaseCustomTableViewCell *cell = (BaseCustomTableViewCell *)[aTableView dequeueReusableCellWithIdentifier:cellId];
if (cell == nil)
{
if ([cellId isEqualToString:@"CellId1"])
{
cell = [[CustomTableViewCell1 alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
}
else
{
cell = [[CustomTableViewCell2 alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
}
}
// the following line seems to be the bottleneck
[self styleBackground:cell indexPath:indexPath totalRows:totalRows];
[cell configureData:myRowData];
}
- (void)styleCellBackground:(BaseCustomTableViewCell *)cell
indexPath:(NSIndexPath *)indexPath
totalRows:(NSInteger)totalRows
{
UIImage *backgroundImage = nil;
if (indexPath.row == 0)
{
// Top row of this section
backgroundImage = self.topRowImage; // ivar loaded during 'viewDidLoad'
}
else if (indexPath.row == totalRows - 1)
{
// Bottom row of this section
backgroundImage = self.bottomRowImage;
}
else {
// Middle row of this section
backgroundImage = self.middleRowImage;
}
[cell updateRowBackground:backgroundImage];
}
@implementation CustomTableViewCell
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])
{
// Create my text field
_textField = [[UITextField alloc] initWithFrame:CGRectZero];
_textField.backgroundColor = [UIColor whiteColor];
self.backgroundColor = [UIColor whiteColor];
self.contentView.backgroundColor = [UIColor whiteColor];
self.backgroundView = [[UIImageView alloc] init];
// not sure which of these should be set to opaque to ensure to meet criteria #4
// 4. Make your UITableViewCell's layer opaque (same goes for the content view if you have one)
self.backgroundView.opaque = YES;
self.layer.opaque = YES;
self.opaque = YES;
self.contentView.opaque = YES;
[self.contentView addSubview:_textField];
}
}
- (void)layoutSubviews
{
CGRect textFieldFrame = CGRectMake(10, 2, 278, 40);
self.textField.frame = textFieldFrame;
[super layoutSubviews];
}
- (void)updateRowBackground:(UIImage *)rowBackground
{
((UIImageView *)self.backgroundView).image = rowBackground;
}