UITableView in UIViewController


There are times when you want to add a UITableView to a UIViewController (without having to use a UITableViewController). To do this, you’ve to make sure to override the implementation of a number of methods in the delegate and data source classes to get the table to work as expected, i.e., to support deletion and insertion of rows. You’ve to remember to make the following changes:

You need to implement some of the methods of the UITableViewDelegate and UITableViewDataSource classes. Don’t forget to declare them in the interface definition. If you’re using the Interface Builder, make sure that you connect the table view to my_table. I forgot to do this step causing much frustration. If you forget this step, the table view object is not created, but calling methods on it don’t fail so you don’t have a easy null pointer exception to help you find the cause.

@interface MyViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
	IBOutlet UITableView *my_table;
        ...
}
@property (nonatomic, retain) IBOutlet UITableView *my_table;
...
@end
...
@implementation
@synthesize my_table;

In addition, you’ll need to define a number of key delegate and data source methods:

#pragma mark UITableViewDelegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{
        // typically you need know which item the user has selected. 
        // this method allows you to keep track of the selection
	mytable_selection_path = indexPath;
}

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView 
		   editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
        // 
	return UITableViewCellEditingStyleDelete; 
} 

Next define the data source methods that you’ll need. The code below assumes the data for the table is kept in the model, here a simple array called “data”.

#pragma mark UITableViewDataSource

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView 
		 cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{	
	UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"any-cell"];
	
	if (cell == nil) {
		cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"any-cell"] autorelease];
	}
	
	// Set up the cell...
	
	int row = indexPath.row;
	@try {
		// get the data from the model for this row
		if (model is being calculated == nil) {
			cell.textLabel.text = @"Loading ...";
		} else {
			cell.textLabel.text = [NSString stringWithFormat: @"%@", model part you wish to display];
			cell.detailTextLabel.text = [NSString stringWithFormat: @"details: ... %@", model details];
		}		
	}
	@catch (NSException * e) {
		return NULL;
	}
	@finally {
	}
	
	return cell;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
	return @" "; //@"Top";
}

- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
{
	return @" "; //@"Bottom";
}

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

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

// Handle deletion/insertion requests 
- (void) tableView:(UITableView *) tableView
	commitEditingStyle:(UITableViewCellEditingStyle) editingStyle 
	forRowAtIndexPath:(NSIndexPath *) indexPath 
{
	if (editingStyle == UITableViewCellEditingStyleDelete) {
		[data removeObjectAtIndex:[indexPath row]]; 
		[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject: indexPath] 
						 withRowAnimation:UITableViewRowAnimationFade];
	} else if (editingStyle == UITableViewCellEditingStyleInsert) {
		NSIndexPath *idx = [NSIndexPath indexPathForRow:[data count]-1 inSection:0];
		NSArray *newPath = [NSArray arrayWithObject:idx];
		[tableView insertRowsAtIndexPaths:newPath withRowAnimation:UITableViewRowAnimationFade];
	}
}

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
       // cherry pick which rows should support deletion
	return (indexPath.row > 1) ? YES : NO;
}

How about deletion and insertion? You need to add some UI element (e.g., a button) to allow the user to “edit” the list.

- (IBAction) add: (id) sender
{
       // get the new object, say b, and add it to the model
	[data addObject:b];
}

- (IBAction) remove: (id) sender
{
	if (remove_button.titleLabel.text == @"Done") {
		[self exit_edit_mode];
		[remove_button setTitle:@"Edit" forState:UIControlStateNormal];
	} else {
		[self enter_edit_mode];
		[remove_button setTitle:@"Done" forState:UIControlStateNormal];
	}
}

- (void) enter_edit_mode
{
	[my_table setEditing:YES animated:YES]; 
}

- (void) exit_edit_mode
{
	[my_table setEditing:NO animated:YES];
}

9 Responses to “UITableView in UIViewController”

  1. Koen Says:

    Dear Shahram,

    I didn’t magage to get my array displayed in my table view, are there any obstacles left? Or could you maybe send my your working code?

    Thanks in advance!

    • Shahram Javey Says:

      Hi. Sorry I don’t have the code anymore. It is now part of a much larger code. If your code is only doing the table and is simple, send it over and I’ll take a look. There are so many little steps that could go wrong, e.g. properly connecting your table from IB to your code, …, forgetting to define all of the needed delegate methods, …

  2. Saad Says:

    There is one step missing, it might be very obvious for experienced iOS programmer but can be very frustrating for a new developer. In Interface Builder, select table and then in Connections tab link delegate and datasource to File’s Owner.

    @koen: I think you are possibly missing the step above.

    @Shahram: It is a nice article and I spent days looking to get Table in View working. BUT your code is incomplete and can be very confusing and frustrating for a new developer. A little more explanation and step by step approach would have made this article superb but anyways it did help me.

  3. Aaron Says:

    mytable_selection_path is undefined…

    Like these guys said, it’s too bad this code is incomplete. Thanks though

  4. mohamad kasim Says:

    It worked perfect.
    thank you

  5. fl0m11 Says:

    I have tested the code but I won’t run. I added the UITableViewDelegate and UITableDataSource to the interface but the delegate and data source methods won’t execute. :-( I am frustrating!!! Have you any idea?

  6. eloril Says:

    anyone doing this these days also requires this in the viewDidLoad:

    [tableView setDelegate:self];
    [tableView setDataSource:self];

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.

%d bloggers like this: