3

I have two custom cells. And I want to display 2 sections in my UITableView. The first section with one row displaying the first custom cell, and the second section displaying a list of objects pulled from core data.

How should I implement the "cellForRowAtIndexpath" method ?

Here is some of my code:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

// Return the number of sections.
return 2;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

// Return the number of rows in the section.
if (section == 0) {
    return 1;

} else if (section == 1) {
   //gastos is an array
   return [self.gastos count];  
}
return 0;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath         *)indexPath
{

switch (indexPath.section) {
    case 0:
    {
        SaldoCelda *cell1 = [tableView dequeueReusableCellWithIdentifier:@"Cell1"      forIndexPath:indexPath];
        return cell1;
    }
    case 1:
    {
        static NSString *CellIdentifier = @"Cell";
        CeldaGasto *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier      forIndexPath:indexPath];

        NSManagedObject *gasto = [self.gastos objectAtIndex:indexPath.row];

        [cell.monto setText:[NSString stringWithFormat:@"%@ AR$", [gasto valueForKey:@"monto"]]];
        [cell.categoria setText:[NSString stringWithFormat:@"%@", [gasto valueForKey:@"categoria"]]];
        [cell.fecha setText:[NSString stringWithFormat:@"%@", [gasto valueForKey:@"fecha"]]];

        return cell;
    }
    default:
        break;
}
return 0;
}

And this is the error message I get:

Assertion failure in -[UITableView _configureCellForDisplay:forIndexPath:], /SourceCache/UIKit_Sim/UIKit-2903.23/UITableView.m:6246 2014-03-05 01:02:57.181 Spendings[2897:70b] * Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'

Thankyou for your help!

Loukas
  • 616
  • 1
  • 6
  • 22
JuanM.
  • 434
  • 1
  • 8
  • 19
  • 3
    Read the error. You are returning `nil` for your `cellForRowAtIndexPath:` method. It's either case 0 or case 1. Use the debugger and see which one is the problem. – rmaddy Mar 05 '14 at 04:31
  • 1
    BTW - a little side note - there is no need for the `break` statements in your `switch` for the cases that end in `return`. The `break` statements will never be reached in those cases. – rmaddy Mar 05 '14 at 04:48
  • You are right!, is it Ok to return 0 at the end of the method? after switch ends? – JuanM. Mar 05 '14 at 04:51
  • Actually, the `return 0;` at the end of `cellForRowAtIndexPath` should be `return nil;` but technically they are the same thing. And the `return 0` will never be reached anyway. – rmaddy Mar 05 '14 at 04:55
  • @JuanM. have to checked my answer and tried – Charan Giri Mar 05 '14 at 05:04
  • I have just made test app with your problem and it works fine, so it could be that you have some problem with cell identifiers, check if you referenced it correctly in your storyboard – AntonijoDev Mar 05 '14 at 11:17

4 Answers4

3

I have made a test and it works fine. These are the steps:

  1. Create UITableViewController in storyBoard
  2. Drag and drop UITableViewCell on a UITableViewController below the cell that is already there
  3. Assign CellIdentifier to both cells (I used Cell1 and Cell2)
  4. Create 2 subclasses of UITableViewCell (I called them Cell1 and Cell2)
  5. Create subclass of UITableViewController and name it somehow
  6. in cellForRowAtIndexPath method:

    static NSString *CellIdentifier = @"Cell1";
    
    static NSString *CellIdentifier1 = @"Cell2";
    
    switch (indexPath.section) {
    
        case 0:
        {
            Cell1 *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
            return cell;
        }
            break;
        case 1:
        {
            Cell2 *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1 forIndexPath:indexPath];
            return cell;
        }
            break;
    
        default:
            break;
    

    }

    return nil;
    

As you can see the implementation is the same as yours

The only way I could reproduce your error is by returning nil in switch block and the documentation for dequeueReusableCellWithIdentifier says:

This method always returns a valid cell.

Even if you messed up your cell identifiers, you still wouldn't get the error you posted. So my conclusion is:

reboot, clean project, restart simulator or something like that cause your scenario according to documentation is not possible...

AntonijoDev
  • 1,317
  • 14
  • 29
0

Beside you are returning nil for one of your cells, you also has an issue in numberOfRowsInSection, you are returning 0 rows for section 1!!, although you are expecting rows in this section in your cellForRowAtIndexPath.

Tarek Hallak
  • 18,422
  • 7
  • 59
  • 68
  • 1
    While the implementation of `numberOfRowsInSection:` is incorrect as you point out, that really has nothing to do with the crash. But it does narrow down the problem in `cellForRowAtIndexPath:` to the `case 0:` code. – rmaddy Mar 05 '14 at 04:43
  • 1
    hmmm, agree 100% ;) but still yet another issue he should take care of it. – Tarek Hallak Mar 05 '14 at 04:46
  • OK, I just fix that, but my problem still goes. The section 0 is only having one row as I want, and the section 1 has the count of "gastos". – JuanM. Mar 05 '14 at 04:47
  • But you haven't fixed the fact that you return `nil` in `case 0` of your `cellForRowAtIndexPath` method. The call to `[tableView dequeueReusableCellWithIdentifier:@"Cell1" forIndexPath:indexPath];` is returning `nil`. Did you register the cell for that index path? Did you register it with the name `Cell1`? – rmaddy Mar 05 '14 at 04:49
  • As @rmaddy mentioned in his comment you need to do some debugging, check why your cell is nil, most likely the Cell Identifier, start from there. – Tarek Hallak Mar 05 '14 at 04:52
  • Or could it be a storyboard problem ? I have my table view with content of "static cells" with sections equals to "2" in Storyboard editor. And the first section with its only cell is registered as Cell1 in its identifier. – JuanM. Mar 05 '14 at 04:56
  • 1
    First the table is not a "static cells" content which has nothing to do with your problem (ignored I guess), second you need to create a prototype cell for section 2 and register it as "Cell" or init it inside your `cellForRowAtIndexPath`. – Tarek Hallak Mar 05 '14 at 04:59
  • Ok, that is helping. Now I do not get any error message. But I got another problem, my first custom cell has the size of the second custom cell. – JuanM. Mar 05 '14 at 05:05
  • 1
    Glad for that, man the cell height is another story, change it using the delegate:- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexpathe.section == 0 && indexpathe.row == 0) return 50.0; return 100; } – Tarek Hallak Mar 05 '14 at 05:08
  • Awesome! That really worked! I just compared the values that I had to return with the heights that I had made in the storyboard editor! Thanks a lot to you @null and rmaddy. – JuanM. Mar 05 '14 at 05:14
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/49011/discussion-between-juanm-and-null) – JuanM. Mar 05 '14 at 05:18
0

you can create set of cell in one xib and fetch it in cellForRowAtindex with it's identifier. Now you can set it's property and data to it.

static NSString *CellIdentifier = @"MyCellIdentifier";

MyCell *cell = (MyCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellIdentifier owner:self options:nil];
cell = (MyCell *)[nib objectAtIndex:0];

 cell1=(MyCell *)[nib objectAtIndex:1];
}
Gourav Gupta
  • 41
  • 1
  • 7
  • 2
    I think the use of XIB files is outdated, and with xCode 5 and iOS 7 everything works with storyboard. – JuanM. Mar 05 '14 at 05:16
  • I actually work with XIB files for creating cells, loading is simplier and focusing better when working on your cell design. But i understand you want to use only Storyboard Maybe you should still give it a try. – Jissay Mar 05 '14 at 08:34
  • you can do the same thing with the help of storyboard. In case of storyboard you have to get cell's nib from your storyboard file. – Gourav Gupta Mar 05 '14 at 08:42
-3

Try This i'm modifying your code

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 2;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
if (section == 0) {
  return 1;
}
else if (section == 2) {
//gastos is an array
return [self.gastos count];  
}
//return 0; you should not write this because at the end of execution of this method it will return 0
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath         *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
switch (indexPath.section) {
case 0:
{
SaldoCelda *cell1 = [tableView dequeueReusableCellWithIdentifier:@"Cell1"      forIndexPath:indexPath];
cell=cell1;
    break; 
}
case 1:
{
static NSString *CellIdentifier = @"Cell";
CeldaGasto *cell2 = [tableView dequeueReusableCellWithIdentifier:CellIdentifier      forIndexPath:indexPath];

NSManagedObject *gasto = [self.gastos objectAtIndex:indexPath.row];
[cell.monto setText:[NSString stringWithFormat:@"%@ AR$", [gasto valueForKey:@"monto"]]];
[cell.categoria setText:[NSString stringWithFormat:@"%@", [gasto valueForKey:@"categoria"]]];
[cell.fecha setText:[NSString stringWithFormat:@"%@", [gasto valueForKey:@"fecha"]]];
cell=cell2;
break;
}
default:
break;
}
return cell;
//return 0; remove this in your code
}

Hope this will help

Charan Giri
  • 1,097
  • 1
  • 9
  • 15
  • None of these changes are needed and it actually makes the code more confusing. And none of it fixes the problem. – rmaddy Mar 05 '14 at 04:56
  • @rmaddy which part of code made you confused? return 0; means you are returning nil to cell and rows... – Charan Giri Mar 05 '14 at 05:02
  • 1
    I'm not confused. The `return` is never reached. The table has two sections. Therefore `case 0` and `case 1` of the `switch` handles the two sections. Both create and return a cell. The `default` is never reached. The `return` at the end of the method is never reached. The OP's code is much cleaner than your proposal. – rmaddy Mar 05 '14 at 05:06
  • Thank you Charan, but I already solved part of my problem in the answers before. I got what you say @rmaddy about the return is never reached. – JuanM. Mar 05 '14 at 05:09
  • @rmaddy when switch conditions are true The default is never reached. will it? in section 0 and 1 i'm assigning cell1 to cell and cell2 to cell and returning it at the end as return cell; break is used to just break the switch not the cell configure method. so it will reach return cell statement. If i'm wrong on this can you please explain it – Charan Giri Mar 05 '14 at 05:18
  • Sorry, I was talking about the OP's code. My whole point is that your suggested change is unnecessary as well as more complicated. And more importantly, it in no way solves the problem. – rmaddy Mar 05 '14 at 05:21