Reputation: 493
I have a Core Data backed table view, that show a list of editable fields, for different field types I have different UTableViewCells with different cell identifiers. When I scroll too quickly in the simulator or try to "bounce" past the last cell, I get a crash, saying that UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath. The whole problem goes away if I remove the dequeueReusableCellWithIdentifier: steps. Which means my table view is less efficient. I'm at most using 20 fetched objects (more along the lines of 8-10) in my table view, so the inefficiency might be a minor issue. I'd just like to know if I'm doing something the wrong way.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Field *aField = [self.fetchedResultsController objectAtIndexPath:indexPath];
static NSString *CellIdentifier = @"Cell";
static NSString *ChoiceIdentifier = @"ChoiceCell";
static NSString *SwitchIdentifier = @"SwitchCell";
UITableViewCell *cell;
if ([aField.fieldType isEqualToString:@"choice"] || [aField.fieldType isEqualToString:@"date"] || [aField.fieldType isEqualToString:@"multiChoice"] ) {
NSLog(@"ChoiceCell");
cell = [tableView dequeueReusableCellWithIdentifier:ChoiceIdentifier];
if (cell == nil) {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[[NSBundle mainBundle] loadNibNamed:@"ChoiceTableViewCell-iPad" owner:self options:nil];
} else {
[[NSBundle mainBundle] loadNibNamed:@"ChoiceTableViewCell" owner:self options:nil];
}
}
} else if ([aField.fieldType isEqualToString:@"boolean"]){
NSLog(@"SwitchCell");
cell = [tableView dequeueReusableCellWithIdentifier:SwitchIdentifier];
if (cell == nil) {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[[NSBundle mainBundle] loadNibNamed:@"SwitchTableViewCell-iPad" owner:self options:nil];
} else {
[[NSBundle mainBundle] loadNibNamed:@"SwitchTableViewCell" owner:self options:nil];
}
}
} else {
NSLog(@"Cell");
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[[NSBundle mainBundle] loadNibNamed:@"EditableTableViewCell-iPad" owner:self options:nil];
} else {
[[NSBundle mainBundle] loadNibNamed:@"EditableTableViewCell" owner:self options:nil];
}
}
}
cell = editableCell;
self.editableCell = nil;
// Configure the cell...
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
Additional Details: The editableCell is being set as in each of the NIBs that correspond to the custom cells. I tried more directly setting this by saying
dynamicCell = [[[NSBundle mainBundle] loadNibNamed:@"ChoiceTableViewCell-iPad" owner:self options:nil] objectAtIndex:0];
but still had the same problem. It should never return nil. The all the NIBs are being loaded as long as I don't scroll too fast. I've double and triple checked the NIB names to make sure.
Here's the updated working code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Field *aField = [self.fetchedResultsController objectAtIndexPath:indexPath];
static NSString *CellIdentifier = @"Cell";
static NSString *ChoiceIdentifier = @"ChoiceCell";
static NSString *SwitchIdentifier = @"SwitchCell";
if ([aField.fieldType isEqualToString:@"choice"] || [aField.fieldType isEqualToString:@"date"] || [aField.fieldType isEqualToString:@"multiChoice"] ) {
NSLog(@"ChoiceCell");
dynamicCell = [tableView dequeueReusableCellWithIdentifier:ChoiceIdentifier];
if (dynamicCell == nil) {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[[NSBundle mainBundle] loadNibNamed:@"ChoiceTableViewCell-iPad" owner:self options:nil];
} else {
[[NSBundle mainBundle] loadNibNamed:@"ChoiceTableViewCell" owner:self options:nil];
}
}
} else if ([aField.fieldType isEqualToString:@"boolean"]){
NSLog(@"SwitchCell");
dynamicCell = [tableView dequeueReusableCellWithIdentifier:SwitchIdentifier];
if (dynamicCell == nil) {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[[NSBundle mainBundle] loadNibNamed:@"SwitchTableViewCell-iPad" owner:self options:nil];
} else {
[[NSBundle mainBundle] loadNibNamed:@"SwitchTableViewCell" owner:self options:nil];
}
}
} else {
NSLog(@"Cell");
dynamicCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (dynamicCell == nil) {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[[NSBundle mainBundle] loadNibNamed:@"EditableTableViewCell-iPad" owner:self options:nil];
} else {
[[NSBundle mainBundle] loadNibNamed:@"EditableTableViewCell" owner:self options:nil];
}
}
}
UITableViewCell *cell;
cell = dynamicCell;
self.dynamicCell = nil;
// Configure the cell...
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
Upvotes: 0
Views: 1546
Reputation: 21967
Looks like the problem is with:
cell = editableCell
if editableCell
is nil your app will crash. I assume you intend editableCell
to be set by loadNibNamed:
. It is not set if you dequeue a cell.
Upvotes: 4