devxlogo

iPhone Programming: Displaying Data with the Table View

iPhone Programming: Displaying Data with the Table View

ne of the most commonly used views in iPhone applications is the Table View, which you use to display lists of items. Users can select a visible item, or tap to display more information. Figure 1 shows a Table View in action in the Settings application.

 
Figure 1. iPhone Settings: The iPhone displays items in the Settings application in a Table View.

This article shows how you can use the Table View in the iPhone SDK to display rows of data. In particular, you will learn the events you need to handle to populate the Table View with items and let users select items; how to display text and images in Table View rows, and how to add “disclosure buttons” to rows in a Table View, which are iconic buttons that let users know more information is available.

A Simple Table View

 
Figure 2. New Navigation-Based Project: To create a new Navigation-based Application project, select the project icon in Xcode.

To begin building a sample Table View application, open Xcode, and select the Navigation-based Application project (see Figure 2), which includes a Table View. Click the Choose button, and name the new project TableViewExample.

The new project contains a file named RootViewController.xib located in the Resources folder. Double-click on the RootViewController.xib file to open it in Interface Builder. Figure 3 shows the RootViewController.xib window together with the contents of the Table View item.

 
Figure 3. RootViewController.xib File: Here’s the contents of the RootViewController.xib file shown in Interface Builder.

 
Figure 4. Table View Connections: Right-clicking on the Table View in Interface Builder shows you all its connections.

Unlike a View-based Application project, a Navigation-based Application project uses a default Table View rather than a View item, because a Table View is often used together with a Navigation controller.

Right-click on the Table View item in the RootViewController.xib window to view its connections (see Figure 4). Observe that the two Outlets labeled dataSource and delegate are both connected to the File's Owner item, which in turn points to the RootViewController class (implemented by the RootViewController.h and RootViewController.m files).

The two outlets serve the following functions:

  • The dataSource outlet indicates what item should provide the implementation for the various methods that populate the Table View with rows. In this case, the connection indicates that the RootViewController class (File's Owner) should do that.
  • The delegate outlet indicates what item should implement the various methods that allow users to select rows in the Table View. In this case, the connection also indicates that the RootViewController class (File's Owner) should do that.
  • Populating Table View Rows

    To populate the Table View with rows, you need to implement a couple of methods in the RootViewController.m file. Add the statements shown in Listing 1, which create a mutable array of states in the U.S.

    Next, implement the tableView:numberOfRowsInSection: method, which controls how many rows you want the table view to display. The following code sets it to the number of items in the listOfStates array, to specify how many rows you want to populate in the Table View:

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

Next, implement the tableView:cellForRowAtIndexPath: method, which inserts a cell in a particular location of the Table View. This event fires once for each row of the Table View; however, the method is not called continuously from start to finish. For example, if there are 100 rows to be displayed, it will be fired continuously for the visible rows. Then, when the user scrolls down the table view, the tableView:cellForRowAtIndexPath: method gets called for the next set of visible rows. The following code retrieves an individual item from the listOfStates array and inserts it into the table view.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {    static NSString *CellIdentifier = @"Cell";    UITableViewCell *cell = [tableView     dequeueReusableCellWithIdentifier:CellIdentifier];    if (cell == nil) {        cell = [[[UITableViewCell alloc]             initWithStyle:UITableViewCellStyleDefault             reuseIdentifier:CellIdentifier]             autorelease];    }        NSString *cellValue = [listOfStates objectAtIndex:indexPath.row];    cell.textLabel.text = cellValue;        return cell;}
 
Figure 5. Populated Table View: Here’s the sample application running in the iPhone simulator, showing the rows inserted in the Table View.

Specifically, you use the dequeueReusableCellWithIdentifier: method of the UITableView class to obtain an instance of the UITableViewCell class. The dequeueReusableCellWithIdentifier: method returns a reusable table view cell object. This is important because if you have a large table, with perhaps 10,000 rows, creating a single UITableViewCell object for each row would carry a huge performance and memory penalty. And because a Table View will display only a fixed number of rows at any one time, it would make sense to reuse the cells that have been scrolled out of view. This is exactly what the dequeueReusableCellWithIdentifier: method does.

For example, if there are 10 visible rows in the table view, only 10 UITableViewCell objects are ever created—those 10 get reused as the user scrolls through the table view.

That’s enough to get started. Press Command-R to test the application on the iPhone Simulator. Figure 5 shows the populated Table View displayed in the iPhone Simulator.

Adding a Header and Footer

You can display a header and footer for the table view by simply implementing the following two methods in the RootViewController.m file:

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{return @"States";}- (NSString *)tableView:(UITableView *)tableViewtitleForFooterInSection:(NSInteger)section {return @"USA";}
 
Figure 6. Header and Footer: Here’s the Table View displaying a header and footer.

When you re-run the application, you’ll see a header and footer as shown in Figure 6.

Adding an Image

In addition to displaying text, you can also display an image in a Table View cell. Drag-and-drop the image named USA.jpeg (you’ll find it in the downloadable code for this article) to the Resources folder in Xcode. When prompted, ensure that you save a copy of the image in your project. Figure 7 shows the image added to the project.

 
Figure 7. New Image: After adding the USA.jpeg image to the Resources folder of the project, you can view it in Xcode.

To display the image next to the cell text in the Table View, insert the following statements in the tableView:cellForRowAtIndexPath: method:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {    static NSString *CellIdentifier = @"Cell";        UITableViewCell *cell = [tableView        dequeueReusableCellWithIdentifier:CellIdentifier];    if (cell == nil) {        cell = [[[UITableViewCell alloc]             initWithStyle:UITableViewCellStyleDefault             reuseIdentifier:CellIdentifier]             autorelease];    }

 
Figure 8. Added Images: Note that each Table View cell now displays an image as well as text in each row.
    NSString *cellValue = [listOfStates objectAtIndex:indexPath.row];    cell.textLabel.text = cellValue;        UIImage *image = [[UIImage imageNamed:@"USA.jpeg"]         _imageScaledToSize:CGSizeMake(30.0f, 32.0f)        interpolationQuality:1];    cell.imageView.image = image;        return cell;}

You may have noticed in the preceding code that the UITableViewCell object already has an ImageView.image property. All you need to do is to create an instance of the UIImage class and load the image from the Resources folder of your project. To scale the image, you can use an undocumented property of the UIImage class: imageScaledToSize:, which will trigger a warning in Xcode (which you can ignore).

Press Command-R to test the application and you'll see the flag image displayed next to each row (see Figure 8).

Displaying the Item Selected

So far, you've seen how to populate the Table View with items. Now you'll see how to let users make selections in a Table View.

Implement the tableView:didSelectRowAtIndexPath: method in the RootViewController.m file as follows:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {        NSString *stateSelected =       [listOfStates objectAtIndex:[indexPath row]];    NSString *msg = [[NSString alloc] initWithFormat:    @"You have selected %@", stateSelected];    UIAlertView *alert =       [[UIAlertView alloc] initWithTitle:@"State selected"          message:msg          delegate:self          cancelButtonTitle:@"OK"          otherButtonTitles:nil];            [alert show];         [alert release];    [stateSelected release];    [msg release]; }

The didSelectRowAtIndexPath: method gets called whenever the user selects a row in the Table View. One of the even parameters is of type NSIndexPath, which represents the path of a specific item in a nested array collection.

 
Figure 9. Selected Row Alert: You'll see this alert when you select a row in the Table View.

To know which row has been selected, you simply call the row property of the NSIndexPath object (indexPath) and then use the row number as an index into the listOfStates array:

NSString *stateSelected = [listOfStates objectAtIndex:[indexPath row]];
Author's Note: The NSIndexPath class's row property is one of the additions made by the UIKit framework to enable the identification of rows and sections in a Table View. Hence, be aware that the original NSIndexPath class definition does not contain the row property.

Press Command-R to test the application on the iPhone Simulator. When you select a row by tapping on it, you'll see an alert view showing the selected row (see Figure 9).

Navigating to Another View When a Row Is Selected

One very common operation with a Table View when a user selects a row is to display details of the selected row in another View window. To do that, add a new XIB file and its corresponding view controller to your project. Right-click on the Classes folder in Xcode and select Add ? New File….

Under the Cocoa Touch Class category, select the UIViewController subclass template, ensure the “With XIB for user interface” option is selected (see Figure 10), and click Next.

 
Figure 10. Adding a New View: The figure shows the screen for adding a new UIViewController subclass item to the project.
 
Figure 11. New View Files: Creating the new View adds three files to the sample project.

Name the new class DetailsViewController.m, and click Finish. Xcode should now have three additional files as shown in Figure 11.

 
Figure 12. New View with Label: Add a Label view to the View window and resize it as shown here.

Double-click the DetailsViewController.xib file to edit it in Interface Builder. Drag and drop a Label view onto the View window (see Figure 12).

Type the following statements in the DetailsViewController.h file:

#import @interface DetailsViewController : UIViewController {    IBOutlet UILabel *label;    NSString *textSelected;}@property (nonatomic, retain) UILabel *label;@property (nonatomic, retain) NSString *textSelected;-(id) initWithTextSelected:(NSString *) text;@end

Next, enter the following statements in the DetailsViewController.m file:

#import "DetailsViewController.h"@implementation DetailsViewController@synthesize label;@synthesize textSelected;-(id) initWithTextSelected:(NSString *) text {    self.textSelected = text;    [label setText:[self textSelected]];    return self;}- (void)viewDidLoad {    [label setText:[self textSelected]];    self.title = @"Movie Details";    [super viewDidLoad];}
 
Figure 13. Making Connections: Connect the label outlet to the Label view.
- (void)dealloc {    [textSelected release];    [label release];    [super dealloc];}@end

Save the project in Xcode. Back in Interface Builder, control-click and drag the File's Owner item onto the Label view (see Figure 13). Select the label.

 
Figure 14. Navigating to Another View: Selecting a state row now navigates to a second View window that displays the selected state.

Back in Xcode, add the following statements to the RootViewController.h file:

#import "DetailsViewController.h"@interface RootViewController : UITableViewController {    DetailsViewController *detailsViewController;}@property (nonatomic, retain)    DetailsViewController *detailsViewController;@end

Finally, add the code in Listing 2 to the RootViewController.m file.

Press Command-R to test the application. Now, selecting a row redirects you to another View window that displays the selected state (see Figure 14).

Displaying a Disclosure Button

The rows in a Table View can also optionally display additional buttons, such as the Detail Disclosure Button shown in Figure 15.

 
Figure 15. Detail Disclosure Buttons: This Table View displays detail disclosure buttons in each row.

To display the disclosure button, you need to set the UITableView object's accessoryType property in the tableView:cellForRowAtIndexPath: method. Add the following code to the method:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {    static NSString *CellIdentifier = @"Cell";        //...    UIImage *image = [[UIImage imageNamed:@"USA.jpeg"]        _imageScaledToSize:CGSizeMake(30.0f, 32.0f)       interpolationQuality:1];    cell.imageView.image = image;        cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;            return cell;}

A detail disclosure button has two clickable regions: the row and the button itself. A user click on a row still fires the tableView:didSelectRowAtIndexPath: method (just like the previous examples). But a click on the detail disclosure button fires the tableView:accessoryButtonTappedForRowWithIndexPath: method instead. Therefore, you need to modify the tableView:didSelectRowAtIndexPath: method as follows:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {    NSString *stateSelected = [listOfStates objectAtIndex:      [indexPath row]];    NSString *msg = [[NSString alloc] initWithFormat:      @"You have selected %@", stateSelected];                        UIAlertView *alert = [[UIAlertView alloc]        initWithTitle:@"State selected"        message:msg        delegate:self        cancelButtonTitle: @"OK"        otherButtonTitles:nil];        [alert show];         [alert release];        [msg release];    }

You also need to implement the tableView:accessoryButtonTappedForRowWithIndexPath: method as follows:

- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {    NSString *stateSelected = [listOfStates objectAtIndex:      [indexPath row]];    NSString *msg = [[NSString alloc] initWithFormat:      @"You have selected %@",     stateSelected];        //---Navigate to the details view---    if (self.detailsViewController == nil)    {                DetailsViewController *d = [[DetailsViewController alloc]             initWithNibName:@"DetailsViewController"             bundle:[NSBundle mainBundle]];                self.detailsViewController = d;        [d release];    }            //---set the state selected in the method of the     // DetailsViewController---//    [self.detailsViewController initWithTextSelected:msg];    [self.navigationController        pushViewController:self.detailsViewController     animated:YES];        [msg release];    }

Press Command-R to test the application. Now, clicking on a row in the Table View displays the alert view, while clicking on the detail disclosure button navigates to the other View window.

At this point, you've seen the basic operations involved in creating, populating, and handling events for the Table View in the iPhone SDK. Fully understanding how the Table View works is important, because is a very versatile view. The next article in this iPhone development series will reveal some more Table View tricks.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist