18

I'm trying to display a TableView of a list of songs in a user's library. I used the code from this tutorial (which uses a storyboard, but I would like to try it a different way and with just a subclass of UITableView).

I get the error:

*** Assertion failure in -[UITableView dequeueReusableCellWithIdentifier:forIndexPath:], /SourceCache/UIKit/UIKit-2903.23/UITableView.m:5261
2014-05-07 20:28:55.722 Music App[9629:60b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'unable to dequeue a cell with identifier Cell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'

and an error Thread 1: SIGABRT on the line:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

This is my code:

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    MPMediaQuery *songsQuery = [MPMediaQuery songsQuery];
    NSArray *songs = [songsQuery items];

    return [songs count];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    // Configure the cell...

    MPMediaQuery *songsQuery = [MPMediaQuery songsQuery];
    NSArray *songs = [songsQuery items];

    MPMediaItem *rowItem = [songs objectAtIndex:indexPath.row];

    cell.textLabel.text = [rowItem valueForProperty:MPMediaItemPropertyTitle];
    cell.detailTextLabel.text = [rowItem valueForProperty:MPMediaItemPropertyArtist];

    cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Table-view-background.png"]];
    cell.textLabel.textColor = [UIColor colorWithRed:0.278 green:0.278 blue:0.278 alpha:1.0];

    cell.selectedBackgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Table-view-selected-background.png"]];

    cell.textLabel.backgroundColor = [UIColor clearColor];
    cell.detailTextLabel.backgroundColor = [UIColor clearColor];

    return cell;
}

The app loads and works fine, showing a blank table when I run it in the iPhone simulator on my Mac. it comes up with this error when I run it on my iPhone.

Any help would be much appreciated, thanks!

rmaddy
  • 314,917
  • 42
  • 532
  • 579
WunDaii
  • 2,322
  • 4
  • 18
  • 26
  • 1
    This should work if you've set the identifier for your cell in the storyboard to "Cell". Have you? – rdelmar May 07 '14 at 19:38
  • I'm not using storyboards. I went to File > New File > Objective-C Class > created songsTableViewController as a subclass of UITableViewController – WunDaii May 07 '14 at 19:42
  • possible duplicate of [Assertion failure in dequeueReusableCellWithIdentifier:forIndexPath:](http://stackoverflow.com/questions/12737860/assertion-failure-in-dequeuereusablecellwithidentifierforindexpath) – Matthias Bauch May 07 '14 at 20:19

6 Answers6

34

If you create the table view programmatically, and you're just using the default UITableViewCell, then you should register the class (in viewDidLoad is a good place). You can also do this for a custom class, but only if you create the cell (and its subviews) in code (use registerNib:forCellWithReuseIdentifier: if the cell is made in a xib file).

[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];

However, this will only give you a "Basic" table view cell with no detailTextLabel. To get that type of cell, you should use the shorter dequeue method, dequeueReusableCellWithIdentifier:, which doesn't throw an exception if it doesn't find a cell with that identifier, and then have an if (cell == nil) clause to create the cell,

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
    }
    //Configure cell
   return cell;
}
veducm
  • 5,933
  • 2
  • 34
  • 40
rdelmar
  • 103,982
  • 12
  • 207
  • 218
20

Please, if you're using a custom class for your cell check that you've already registered the nib for the cell to use in your table view, as follow:

[self.yourTableViewName registerNib:[UINib nibWithNibName:@"YourNibName" bundle:nil]
         forCellWithReuseIdentifier:@"YourIdentifierForCell"];

Apart from that please check that your custom UITableViewCell subclass has the appropiate reuse identifier.

If you're not using a custom class, please follow this instructions from Apple Docs:

The data source, in its implementation of the tableView:cellForRowAtIndexPath: method, returns a configured cell object that the table view can use to draw a row. For performance reasons, the data source tries to reuse cells as much as possible. It first asks the table view for a specific reusable cell object by sending it a dequeueReusableCellWithIdentifier:

For complete information, please go to this link: Creating a Table View Programmatically.

I hope this helps!

Zev Eisenberg
  • 8,080
  • 5
  • 38
  • 82
Barbara R
  • 1,057
  • 5
  • 18
11

The reason for the crash is that you are using

[tableView dequeueReusableCellWithIdentifier: forIndexPath:]

which will cause a crash unless you specify a cell or nib file to be used for the cell.

To avoid the crash, use the following line of code instead

[tableView dequeueReusableCellWithIdentifier:];

This line of code will return nil if there is not a cell that can be used.

You can see the difference within the docs which can be found here.

There is also a good answer to a Q&A that can be found here

Community
  • 1
  • 1
Fernando
  • 241
  • 3
  • 10
  • Thanks you so much. I haven't notice the difference between these two methods. – xi.lin May 13 '15 at 13:18
  • wrong! if you do this you will get this error: "UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:" – Rashid Jul 31 '15 at 17:00
3

I know this is a bit late to answer this question but here is what I was missing.

I was doing:

let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath)

But I should be doing this:

let cell = self.tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath)

Notice: the self. added next to tableView. I hope this saves you 24 hours.

Jsonras
  • 1,120
  • 13
  • 10
2

if you use default UITableViewCell (not customize one) [tableView dequeueReusableCellWithIdentifier: forIndexPath:], you must registerClass or registerNib; (dequeReusableCellIdentifier:forIndexPath won’t return nil cell, if the cell is not there, then it will automately create a new tableViewCell with the default UITableViewCellStyelDefault!)

otherwise, you can use [tableView dequeueReusableCellWithIdentifier] without registerClass or registerNib

Rachel
  • 237
  • 1
  • 7
0

If you are using StoryBoard then select that tableviewcontroller->table->Cell, give that Cell a 'Identifier' in attribute inspector. Make sure you use the same 'Identifier' in 'cellforrowatindexpath' method.

Kazmi
  • 593
  • 1
  • 6
  • 24