Till today I thought I understood UITableView properly but that perception has changed as I have been fighting scrolling and content mismatch while scrolling issues.
I have a small table view with potentially 20-30 rows depending on user content. When I scroll (a bit faster than usual), the content gets mixed up. Some accessory views get interchanged, background colors get swapped or overwritten; sometimes even the text changes.
I use reuse identifiers for some of cells but I am not sure its even working out properly.
Issues:
Clearly a single reuse identifier is not cutting it in case — as the first and the last cell swap values.
With 3 reuse identifiers for first, last and remaining cells (contain settings), the accessory views get interchanged between some cells that contain settings, i.e. in some cases I use switch controls, in others I use an accessory detail button and there is blasphemy.
Even with 5 reuse identifiers for different types of content, the accessory views get mismatched with background colors of other cells.
I have been writing table views for a while and I have never encountered these issues before. So I have one simple question — When do you create reuse identifiers?
- only when the text/image content is different?
- when accessory views are same? i.e. for different accessory views create different reuse identifiers
I am completely lost on this so if you can really churn out an explanation, I would be really grateful.
EDIT: I have been working on this for the last 5 hours and have gone through a lot of literature and open/closed issues on StackOverflow. I understand what reusable cells are. The provided thread doesn't answer the very specific questions.
Here is some code:
// previously had 3 different types of cells; currently doing with one only
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell)
{
cell = [[ESBasicTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (NSString *)cellIdentifierForIndexPath:(NSIndexPath *)indexPath
{
static NSString *FirstCellId = @"First";
static NSString *SecondCellId = @"Second";
static NSString *ThirdCellId = @"Third";
static NSString *ForthCellId = @"Forth";
static NSString *FifthCellId = @"Fifth";
static NSString *SixthCellId = @"Sixth";
NSString *cellIdentifier = nil;
if (indexPath.section == kSectionFirst && indexPath.row == kRowFirst)
{
cellIdentifier = FirstCellId;
}
else if (indexPath.section == kSectionFirst && indexPath.row == kRowSecond)
{
cellIdentifier = SecondCellId;
}
else if (indexPath.section == kSectionSecond)
{
cellIdentifier = ThirdCellId;
}
else if (indexPath.section == kSectionThird)
{
cellIdentifier = ForthCellId;
}
else if (indexPath.section == kSectionSettings)
{
cellIdentifier = FifthCellId;
}
else if (indexPath.section == kSEctionFifth)
{
cellIdentifier = SixthCellId;
}
return cellIdentifier;
}
The configureCell:atIndexPath
method results in other configuration calls; one of them being configuration for settings:
- (void)configureCellForSettings:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
cell.selectionStyle = UITableViewCellSelectionStyleNone;
switch (indexPath.row)
{
case kRowNotificationSetting:
{
cell.textLabel.text = @"Notifications";
cell.accessoryType = UITableViewCellAccessoryDetailButton;
cell.imageView.image = [[UIImage imageNamed:@"cell_notification_icon"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
break;
}
case kRowSomeOtherSetting:
{
cell.textLabel.text = @"Auto";
cell.imageView.image = [[UIImage imageNamed:@"cell_auto_icon"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UISwitch *switchView = [[UISwitch alloc] initWithFrame:CGRectZero];
[switchView addTarget:self action:@selector(changed:) forControlEvents:UIControlEventValueChanged];
[switchView setOn:...];
cell.accessoryView = switchView;
break;
}
default:
break;
}
}
Some meaningful text has been stripped out (unfortunately). The forth section is for the settings but this is just an example.
Edit: Here is configureCell:atIndexPath:
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == kSectionFirst)
{
// ...
[self configureFirstCell:cell atIndexPath:indexPath];
}
else if (indexPath.section == kSectionSecond)
{
// ...
[self configureSecondCell:cell atIndexPath:indexPath];
}
else if (indexPath.section == kSectionThird)
{
// add ...
[self configureThirdCell:cell atIndexPath:indexPath];
}
else if (indexPath.section == kSectionSettings)
{
// settings
[self configureCellForSettings:cell atIndexPath:indexPath];
}
else if (indexPath.section == kSectionFifth)
{
// delete button
[self configureFifthCell:cell atIndexPath:indexPath];
}
}
Please note — I had to rename a lot of the code to have it on StackOverflow.