How to Create and Populate a UITableView

It seems like every time I create an iOS application I use the UITableView. It’s a very common control found in a lot of applications, however it’s also one of the most difficult controls to use. Every time I use one I have to go out and find examples so I can remember what I’m supposed to do. Because of that, I decided to create a basic tutorial that wraps up the most common usage patterns for the UITableView.

I’m going to start with an empty Window-based application. If you’re new to iOS development, we’ve got a good starter tutorial that will help you get on your feet. Next I’m going to create a UIViewController subclass called MyTableViewController.

New File Dialog

Remember to modify the app delegate to display our new view.

(BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
   
    // Override point for customization after application launch.
 
  tableViewController = [[MyTableViewController alloc]
                         initWithNibName:@"MyTableViewController" bundle:nil];
  [window addSubview:tableViewController.view];
   
  [window makeKeyAndVisible];
   
  return YES;
}

Along with the view controller, a .xib file was also created. Let’s double-click that to bring up Interface Builder. The first thing we need to do is drag a Table View onto our new view.

Drag Table View

The Table View gets all its functionality through a delegate and a data source. The data source is called upon when it needs to know what data to display. The delegate is used to provide feedback – like when a selection is made. What we’re going to do is make our new view controller implement both of these. The first thing we need to do is make the connections in Interface Builder. With the Table View selected, view the “Connections Inspecter”. At the top of the outlets section you’ll see the two outlets I just mentioned. Grab those dots with your mouse and drag them to the Documents Window and drop them on the item named “File’s Owner”. This is what represents our MyTableViewController class.

Setting Outlets

We’re now done with Interface Builder – save the document and return to Xcode. We now need to tell our new class to implement these protocols. This will be done in the header – MyTableViewController.h.

#import <UIKit/UIKit.h>

@interface MyTableViewController :
  UIViewController <UITableViewDataSource, UITableViewDelegate> {

}

@end

That’s actually it for the header file – we can now move on to some implementation. If you built the project now you’d see some warnings for incomplete implementations. This is because we haven’t provided the needed functions to be a data source or delegate.

Let’s start with the data source. There are only two required methods to be a UITableViewDataSource. You have to provide the number of rows and provide cells to display. Let’s start with the number of rows.

(NSInteger)tableView:(UITableView *)tableView
 numberOfRowsInSection:(NSInteger)section {
  return 10;
}

What we’re creating is the simplest form of table – it contains one section with some rows. In this case, I’m telling the table it will have ten rows. The next thing we need to do, and by far the most complicated, is provide cells for the table to display. The reason this is so complicated is because cells can (and should) be reused in order to reduce memory and improve performance. I’ll just stick the code out there first and explain it afterwards.

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

  // Identifier for retrieving reusable cells.
  static NSString *cellIdentifier = @"MyCellIdentifier";
 
  // Attempt to request the reusable cell.
  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
 
  // No cell available – create one.
  if(cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                  reuseIdentifier:cellIdentifier];
  }
 
  // Set the text of the cell to the row index.
  cell.textLabel.text = [NSString stringWithFormat:@"%d", indexPath.row];
 
  return cell;
}

Starting at the top and working our way down. The first thing we need to do is create a way to identify reusable cells. This is done through a simple static string. I then attempt to dequeue a reusable cell with that identifier. If one is not available, I create a new one. Here I’m initializing a cell with the default cell style and setting its reuse identifier to our static string. The last thing to do is simply set the text of the cell to something – in my case I’m using the row index. You should now be able to build and run this application.

iPhone Example

The last thing we need is some kind of notification when the user selects an item. This is done through the UITableViewDelegate protocol. We only need to implement one method for this functionality.

(void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 
  // Show an alert with the index selected.
  UIAlertView *alert = [[UIAlertView alloc]
                        initWithTitle:@"Item Selected"                        
                        message:[NSString stringWithFormat:@"Item %d", indexPath.row]                    
                        delegate:self      
                        cancelButtonTitle:@"OK"          
                        otherButtonTitles:nil];
        [alert show];
        [alert release];
}

Now, whenever an item is selected an alert will be displayed with the index of the row selected.

Selected Row

And there you have it. We’ve successfully created and populated a UITableView control. I have to say, of all the controls that display a list of data, this one is by far the hardest and most verbose to use. Now whenever you need to create a Table View, just remember you can come here and copy and paste all the boilerplate code – I know I will. You can download the complete source of this tutorial below. And as always, feel free to ask questions or leave comments.

Leave a Reply

Your email address will not be published. Required fields are marked *