1

I'm trying to load a single custom cell into a UITableView and it keeps throwing an error

UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:

I have no idea why. I have linked my table view cell to the UITableViewCell definition in my code, but it keeps giving me this error. Here is my code; any help would be greatly appreciated.

#import "RegisterDeviceViewController.h"


@implementation RegisterDeviceViewController

@synthesize checkString;
@synthesize cellRegistration;

// The designated initializer.  Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
/*
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization.
    }
    return self;
}
*/


//Change UITableView Style to Grouped
- (id)initWithStyle:(UITableViewStyle)style {
    // Override initWithStyle: if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
    style = UITableViewStyleGrouped;
    if (self = [super initWithStyle:style]) {
    }
    return self;
}

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    self.title = @"Registration";
    [super viewDidLoad];
}


// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{
    return 1;
}

// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{
    return 1;
}


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

    if (indexPath.section == 1) {
        if (indexPath.row == 1) {
            return cellRegistration;

        }
    }
    return nil;
}


//Pass search type over to rootViewController section2
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{

    /*
     <#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@"<#Nib name#>" bundle:nil];
     // ...
     // Pass the selected object to the new view controller.
     [self.navigationController pushViewController:detailViewController animated:YES];
     [detailViewController release];
     */
}

/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations.
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc. that aren't in use.
}

- (void)viewDidUnload {
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}


- (void)dealloc {
    [super dealloc];
}


@end
jscs
  • 63,694
  • 13
  • 151
  • 195
tinhead
  • 385
  • 2
  • 10
  • 29
  • CellRegistration is a UITableViewCell that I have have create then linked to a custom tableview cell in interface builder. – tinhead May 06 '11 at 04:39

4 Answers4

11

Okay. That's not how UITableView works. When the table view needs to draw a cell (ie, a row); it invokes tableView:cellForRowAtIndexPath: on the object specified in the dataSource property. It's your job to return a UITableViewCell from that method. This is how Apple does it (and how you should do it):

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AnIdentifierString"];
    if (cell == nil) 
    {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"AnIdentifierString"] autorelease];
    }

    cell.textLabel.text = @"This text will appear in the cell";


    return cell;
}

The number of times that method will be invoked depends on the number of sections in the table view and the number of rows in each section. The process works like this:

  1. Table View invokes the delegate method numberOfSectionsInTableView: on its dataSource (it knows it implements that method because the dataSource must adhere to the UITableViewDataSource protocol).
  2. If numberOfSectionsInTableView: returns a number greater than zero, the table view will invoke the delegate method tableView:numberOfRowsInSection: on the dataSource. So if numberOfSectionsInTableView: returns 2, tableView:numberOfRowsInSection: will be invoked twice.
  3. If each invocation of tableView:numberOfRowsInSection: returns a number greater than zero, the table view will invoke the delegate method tableView:cellForRowAtIndexPath: on the dataSource' So if tableView:numberOfRowsInSection: returns 5, tableView:numberOfRowsInSection: will be invoked five times (once for each individual row).
  4. Your opportunity to customise how that cell appears is after you've received a useable cell, but before it is returned (where 'This text will appear in the cell' appears above). You can do quite a lot here; you should see the Class Reference for UITableViewCell to see everything you can do (all I've done is set it to show 'This text...'). The lines above that are a way for iOS to reuse cells for performance considerations. If you, for example, wanted to show a certain string from an array of strings, you could do this (notice the use of the indexPath variable): cell.textLabel.text = [someArrayYouHave objectAtIndex:indexPath.row];.
Alan Zeino
  • 4,406
  • 2
  • 23
  • 30
  • Question, say if I had my own custom cell how could I load it into that tableviewcell? – tinhead May 06 '11 at 04:05
  • Thanks, I just had a read of UITableViewCell but still unsure. I think I will have a break and come back to this... but at least I'm not having errors. Thanks. – tinhead May 06 '11 at 04:17
  • @Alan, I have built my custom cell in interface builder would this make a difference in the way that I need to code it when trying to load it into a tableviewcell. – tinhead May 06 '11 at 04:41
  • A custom cell in Interface Builder can be made in code exactly the same. You'll just have to do it programmatically: http://jainmarket.blogspot.com/2009/05/creating-custom-table-view-cell.html – Alan Zeino May 06 '11 at 05:25
  • @Alan Zeino That wasn't what @tinhead was asking. Try this: `@interface VIEW { CELL *holder; } @property (nonatomic, retain) IBOutlet CELL *holder; @end - (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { CELL *cell = (CELL *)[aTableView dequeueReusableCellWithIdentifier:@"id"]; if (nil == cell) { [[NSBundle mainBundle] loadNibNamed:@"NibName" owner:self options:nil]; cell = self.holder; self.holder = nil; }` Don't forget to set the file's owner in your custom cell to the type of the custom tableview or tableview delegate class. – AWrightIV Jun 10 '11 at 15:34
  • God, that's ugly in a comment. @tinhead If you ask it as an official question and message me, I'll give you a more readable and full answer. – AWrightIV Jun 10 '11 at 15:36
1

You wrote:

it keeps throwing an error 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:' But I have no idea why..

But your -tableView:cellForRowAtIndexPath: says, in part:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//...
    return nil;
}

After reading the error message and looking at the code, do you not see the problem?

Caleb
  • 124,013
  • 19
  • 183
  • 272
0

New iOS7+ solution optimized for Smoother Scrolling

You already can see old solutions but as far as huge amount of Apps will continue only iOS7+ support here is a way more optimized and correct solution.

Cell initialization

To initialize cell just call dequeueReusableCellWithIdentifier and iOS7+ systems are enough smart to handle if cell == nil or not. If during dequeue cell is nil system will automatically make a cell for you.

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

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellIdentifier" forIndexPath:indexPath];

    return cell;
}

Cell configuration

Then do your entire cell configuration in willDisplayCell method. Just create one method in your class that configures cell and here you go with better performance!

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {

    [self configureCell:cell forRowAtIndexPath:indexPath];
}

- (void)configureCell:(UITableViewCell *)cell
    forRowAtIndexPath:(NSIndexPath *)indexPath {

    // Configure your cell
}
0

You are returning only one section, only one row

the section count and row count starts from 0.

Thats y you are getting this kinda error

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 0) {
        if (indexPath.row == 0) {
               //this checking is no necessary, anyway if you want use like this
               //ensure that cellRegistration is UITableViewCell
            return cellRegistration;
        }
    }
    return nil;
}

Also refer this post for loading custom cells.

Community
  • 1
  • 1
KingofBliss
  • 15,055
  • 6
  • 50
  • 72
  • Okay, with regards to loading the nib name.. do I make a new nib with just a custom cell on it for this method? – tinhead May 06 '11 at 04:26
  • Jus now i saw your comment on cellRegistration. Check my edited answer. And check whether it works. – KingofBliss May 06 '11 at 05:26