Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to properly use "dequeueReusableCellWithIdentifier:" with multiple identifiers?
    primarykey
    data
    text
    <p>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 <strong>UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath</strong>. 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. </p> <pre><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"; 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; } </code></pre> <p><strong>Additional Details:</strong> 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</p> <pre><code>dynamicCell = [[[NSBundle mainBundle] loadNibNamed:@"ChoiceTableViewCell-iPad" owner:self options:nil] objectAtIndex:0]; </code></pre> <p>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.</p> <p><strong>Here's the updated working code:</strong></p> <pre><code>- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath </code></pre> <p>{</p> <pre><code>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; </code></pre> <p>}</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload