UITableView – Loading a detail view

The purpose of a UITableView is to display a list of items, from which a user can select one item to see it’s detail view. The navigation that happens between the table view and the detail view is controlled by the navigation controller. In this tutorial we will see how to navigate to a detail view.

Introduction
In this tutorial, you will learn how to navigate to the detail view and also pass some data at the same time. This is the second tutorial in the UITableView tutorial series and inherits its source code from the first tutorial.

Creating a detail view
Open Interface Builder and click on File -> New -> (select Cocoa Touch) View, save it in the application directory and name it “DetailView”. You will be asked to add the view to the current project, click on “Add”. You may need to drag the view (in XCode) to the “Resources” folder. Now that you have your view, we will create a view controller class to control the view on the screen. In XCode select Classes then click on File -> New File -> (under iPhone OS) select UIViewController subclass and name it “DetailViewController, do not change the extension. Now we have to connect the view to the view controller we just created. In Interface Builder, select File’s Owner and open Identity Inspector, under class Identity set the class to “DetailViewController”, open Connections Inspector and create a connection from the view property to the view object in the nib file.

Now add controls to the view which will display the detail contents. The controls that you may want to add to the view, depends on the data you want to display. We will display the country selected in the table view, so a simple label should do. Drag and drop the label on the view. We need some way to change the text of the label from XCode, create a variable of type UILabel in xcode and connect it with the label object on the view. The label should be declared with IBOutlet property, so it shows up in the Connections Inspector. This is how the code looks like

//DetailViewController.h
#import <UIKit/UIKit.h>

@interface DetailViewController : UIViewController {

IBOutlet UILabel *lblText;
}

@end

//Dealloc method declared in DetailViewController.m
- (void)dealloc {

[lblText release];
[super dealloc];
}

After you have declared the variable, open IB and connect the variable to the label placed on the view in Connections Inspector. Now we can change the label’s properties from XCode.

Navigate to the detail view
The method tableView:didSelectRowAtIndexPath is called when a row is selected, it passes the tableview object with the indexPath object to tell us which row was selected. First import the “DetailViewController” class in RootViewController, so it knows about it. The following code will initialize the detail view and display it

//RootViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

DetailViewController *dvController = [[DetailViewController alloc] initWithNibName:@"DetailView" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:dvController animated:YES];
[dvController release];
dvController = nil;
}

A “DetailViewController” is created, initialized with initWithNibName:bundle message and the name of the nib file is passed as the parameter. The view controller is then push to the top of the stack with its animated property set to YES. At last, we clean up memory by releasing the detail view controller. Run the application and now you can select a row to see the detail view.

Passing data
We still have to pass the selected country from the list to the detail view. To do this, we will declare a property in “DetailViewController” whose data type is the same as the in the array, in our case NSString. This is what you have to do if you want to pass data from one view controller to another. The following code declares a property in “DetailViewController”

//DetailViewController.h
#import <UIKit/UIKit.h>

@interface DetailViewController : UIViewController {

IBOutlet UILabel *lblText;
NSString *selectedCountry;
}

@property (nonatomic, retain) NSString *selectedCountry;

@end

//Dealloc method declared in DetailViewController.m
- (void)dealloc {

[selectedCountry release];
[lblText release];
[super dealloc];
}

//First three lines of DetailViewController.m
#import "DetailViewController.h"

@implementation DetailViewController

@synthesize selectedCountry;

The property is synthesized at the top after the implementation begins. Now we can pass the selected country from the table view to the detail view. The tableView:didSelectRowAtIndexPath method looks like this

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

//Get the selected country
NSString *selectedCountry = [listOfItems objectAtIndex:indexPath.row];

//Initialize the detail view controller and display it.
DetailViewController *dvController = [[DetailViewController alloc] initWithNibName:@"DetailView" bundle:[NSBundle mainBundle]];
dvController.selectedCountry = selectedCountry;
[self.navigationController pushViewController:dvController animated:YES];
[dvController release];
dvController = nil;
}

We first get the selected country from the array, initialize the detail view controller, set the selected country to the property on the detail view controller and display it.

Setting the accessory view
Run the app and now we are able to select a row in a table view. However, it is not obvious to the user that a row can be selected to see its detail view. We can add a “accessory view” to the cell which will show up at the right end of the row. The accessory view can be set up in tableView:cellForRowAtIndexPath method or in tableView:accessoryTypeForRowWithIndexPath. We will use the later method to keep our code simple. This is how the source code changes

//RootViewController.m
- (UITableViewCellAccessoryType)tableView:(UITableView *)tableView accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath {

//return UITableViewCellAccessoryDetailDisclosureButton;
return UITableViewCellAccessoryDisclosureIndicator;
}

The above method returns an enum UITableViewCellAccessoryType and we can return four values: UITableViewCellAccessoryNone, UITableViewCellAccessoryDisclosureIndicator, UITableViewCellAccessoryDetailDisclosureButton, and UITableViewCellAccessoryCheckmark. You can test the code by returning one of the four values to see how the accessory view looks like. If you return “UITableViewCellAccessoryDetailDisclosureButton” clicking on the button will not do anything, since the cell is not selected but a button is clicked. The SDK does provide a method which gets called when the accessory button is clicked and that is called tableView:accessoryButtonTappedForRowWithIndexPath. In this method we can call tableView:didSelectRowAtIndexPath which will load the detail view and this is how the code will look like

//RootViewController.m
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {

[self tableView:tableView didSelectRowAtIndexPath:indexPath];
}

The last thing we need to do in detail view controller, is to display the selected country on the label. Do it in viewDidLoad method and this is how the code looks like

// DetailViewController.m
- (void)viewDidLoad {
[super viewDidLoad];

//Display the selected country.
lblText.text = selectedCountry;

//Set the title of the navigation bar
self.navigationItem.title = @"Selected Country";
}

The method “viewDidLoad” gets called when the view is loaded, where we set the selected country by setting the text property of the label “lblText”. The title of the navigation bar is also set in the same method.

Conclusion
We have seen how to display a list of items in a table view, how to select a row and display the detail view, and in the next tutorial we will look at how to search the list of items in a table view. I hope you found this tutorial helpful and if you have any questions, please send me an email. Don’t forget to leave a comment.

Happy Programming,
iPhone SDK Articles


Attachments

Suggested Readings