dequeueReusableCellWithIdentifier returns nil
Asked Answered
I

5

19

I am using a Storyboard's prototype UITableViewCell and getting nil when dequeueReusableCellWithIdentifier is called in cellForRowAtIndexPath. I have triple checked that the Xcode's Identifier for the prototype tableviewcell is "PersonCell", deleted the prototype cell and added it again, commented out the UISearchDisplyDelegate and UISearchBarDelegate inheritance for the UITableViewController, and still get nil. I am stumped. Has anyone run into this?

#import "PeopleGroupPickerViewController.h"
#import "DAL.h"
#import "Person.h"

@interface PeopleGroupPickerViewController ()

@end

@implementation PeopleGroupPickerViewController
{
 NSArray *people;
 NSArray *searchResults;
}

- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:style];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;
 people = [[DAL sharedInstance] getPeople:false];
 [self.tableView registerClass:[GenericDetailCell class] forCellReuseIdentifier:@"PersonCell"];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
 NSString *lastNameSearch = searchText.lowercaseString;
 NSString *firstNameSearch = @"";
 if ([lastNameSearch rangeOfString:@","].length > 0)
 {
  NSArray *names = [lastNameSearch componentsSeparatedByString:@","];
  //NSLog(@"names count",names.count);
  if(names.count > 1)
  {
   lastNameSearch = names[0];
   firstNameSearch = names[1];
   //NSLog(@"first %@ last %@",firstNameSearch,lastNameSearch);
  }
 }

 NSMutableString *predicateText = [[NSMutableString alloc] initWithFormat:@"(sLastName contains[c] '%@')",lastNameSearch];
 if(![firstNameSearch isEqualToString:@""])
 {
  [predicateText appendFormat:@" AND (sFirstName contains[c] '%@')",firstNameSearch];
 }
 NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:predicateText.copy];
 searchResults = [people filteredArrayUsingPredicate:resultPredicate];
 NSLog(@"filterContentForSearchText, searching for %@, # results: %d",predicateText, searchResults.count);
}

-(BOOL) searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
 [self filterContentForSearchText:searchString scope:nil];
 return YES;
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
 if(tableView == self.searchDisplayController.searchResultsTableView)
 {
  return 1;
 }
 else
 {
  return 1;
 }
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
 if(tableView == self.searchDisplayController.searchResultsTableView)
 {
  return searchResults.count;
 }
 else
 {
  return people.count;
 }
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
 GenericDetailCell *cell = [tableView dequeueReusableCellWithIdentifier:@"PersonCell" forIndexPath:indexPath];

 Person_ *thisPerson;
 if(tableView == self.searchDisplayController.searchResultsTableView)
 {
  thisPerson = (Person_ *) searchResults[indexPath.row];
 }
 else
 {
  thisPerson = (Person_ *) people[indexPath.row];
 }
 Person_ *thisSpouse = [[DAL sharedInstance] getSpouse:thisPerson People:people];

 cell.fieldName.text = thisPerson.sName;
 cell.fieldValue.text = thisSpouse.sName;

 return cell;
}
Incept answered 5/8, 2014 at 2:24 Comment(2)
Getting nil from dequeueReusableCellWithIdentifier: is perfectly normal and expected. If it's nil you must create the cell instance. If you registered a cell then use dequeueReusableCellWithIdentifier:forIndexPath:. That won't return nil.Goshawk
rmaddy, the question you referred me to says "With storyboards and tableviews that have prototype cells, [tableView dequeueReusableCellWithIdentifier:] should not return nil.". That question's problem was related to application delegate re-initializing the tableviewcontroller. I am using a plain vanilla UITableViewController in a storyboard, so I'm not sure it is the same problem.Incept
L
23

As maddy stated in the comments, you should create the cell yourself if it is nil, alternatively in your viewDidLoad or where appropriate, you can call one of these methods to make the tableview create the cells for you

Objective-c

[self.tableView registerClass:<#(__unsafe_unretained Class)#> forCellReuseIdentifier:<#(NSString *)#>]
[self.tableView registerNib:<#(UINib *)#> forCellReuseIdentifier:<#(NSString *)#>]

Swift

tableView.register(MyTableViewCell.self, forCellReuseIdentifier: "CellID1")
tableView.register(UINib(nibName: "yourNibName", bundle: nil), forCellReuseIdentifier: "CellID2")
Laurent answered 5/8, 2014 at 2:35 Comment(3)
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"PeopleCell"]; gets past the nil error and binds the table, but it binds the wrong cell class. The prototype cell style is "Right Detail" but it binds a generic UITableViewCell class which I can't bind the detailTextLabel . I worked around this by creating my own custom UITableViewCell subclass and connecting the labels to its outlets.Incept
Just another note: I had to register the custom UITableViewCell subclass for both the regular UITableView (self.tableView) and the search results UITableView (self.searchDisplayController.searchResultsTableView) in viewDidLoad.Incept
Just finished working though a similar situation.. Added code instantiated TableViewController to a parent UIViewController object and then attaching the UITableView within my nib to the UITableViewController that I had just instantiated. Here's the trick I found, #1) Create and add the UITableViewController to your parent view controller. 2) Then find the child UITableView that's in the container view and use the '[childTableVC setTableView:myTableView]'. 3) Then register the cells with the table view. Doesn't work for me when registering cells before adding tableViewController.Comply
F
6

I had this issue after setting the "Restoration ID" in the identity inspector. The correct place to set the reuseIdentifier is the "Identifier" field found in the Attributes inspector.

Fetid answered 19/5, 2017 at 15:7 Comment(0)
M
1

Adding to the @Fonix answer

Make sure that Inherit Module From Target is enabled

enter image description here

Marentic answered 16/1, 2018 at 12:57 Comment(0)
O
1

In my case the problem was from here:

I thought should set Restoration ID in identity inspector:

enter image description here

Whereas should set identifier in attribute inspector:

enter image description here

my code eventually became:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TrueOne") as! TrueOneCell
cell.setup(card: cards[indexPath.row])
return cell

and NO NEED to create instance. If it returns nil, the problem is probably from somewhere else.

Orrin answered 25/8, 2021 at 13:27 Comment(0)
W
0

This can happen if the tableView housing your cell is not assigning your viewcontroller as the delegate and datasource for the tableview as well.

enter image description here

Whipstall answered 14/10, 2018 at 2:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.