iOS Table View Example

UITableView class is used for display and editing List data similar to a ListView in Android. A table view is made up of zero or more sections, each with its own rows. Sections are identified by their index number within the table view, and rows are identified by their index number within a section. Any section can optionally be preceded by a section header, and optionally be followed by a section footer. In this example we display a list of countries grouped by Continents and when the user taps on the accessory button it displays the detail in a new screen using the navigation controller.

The following topics are covered in this tutorial
  • Load Table view data using NSMutable array 
  • Display Table view with multiple sections and rows 
  • Customize display of header and footer for sections 
  • Set height for header, footer and each cell in the Table view 
  • Listen for event when a specific cell is selected 
  • Listen for event when the accessory button is tapped 
  • Display detail information in a new view for a given cell using navigation controller
iOS Table View Example iOS Table View Detail Example

Interface file for Country Object - Country.h

#import <Foundation/Foundation.h>

@interface Country : NSObject

@property (nonatomic, strong) NSString *code;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *continent;
@property (nonatomic, strong) NSNumber *population;

-(id)initWithCode:(NSString *)code_
             name:(NSString *)name_
        continent:(NSString *)continent_
       population:(NSNumber *)population_;

@end

Implementation file for Country Object - Country.m

#import "Country.h"

@implementation Country

@synthesize code;
@synthesize name;
@synthesize continent;
@synthesize population;


-(id)initWithCode:(NSString *)code_
            name:(NSString *)name_
            continent:(NSString *)continent_
            population:(NSNumber *)population_
{
    self = [super init];
    if (self) {
        self.code = code_;
        self.name = name_;
        self.continent = continent_;
        self.population = population_;
    }
    return self;
}

@end

Interface file for Continent Object - Continent.h

#import <Foundation/Foundation.h>

@interface Continent : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSMutableArray *countryList;

@end

Implementation file for Continent Object - Continent.m

#import "Continent.h"

@implementation Continent

@synthesize name;
@synthesize countryList;

@end

Interface file for Root View Controller - CountryViewController.h

#import <UIKit/UIKit.h>
#import "Country.h"
#import "Continent.h"
#import "CountryDetailViewController.h"

@interface CountryViewController : UIViewController
                    <UITableViewDelegate,UITableViewDataSource>

@property (nonatomic, strong) UITableView *myTableView;
@property (nonatomic, strong) NSMutableArray *continentList;

@property (nonatomic, strong) CountryDetailViewController *detailViewController;

@end

Implementation file for Root View Controller - CountryViewController.m

#import "CountryViewController.h"

@interface CountryViewController ()

@end

@implementation CountryViewController

@synthesize myTableView;
@synthesize continentList;
@synthesize detailViewController;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        
        //intialize our data to be displayed in the table view
        [self loadCountryData];
        
    }
    return self;
}

//create mutable array to hold list of countries that will be displayed
- (void) loadCountryData {
    
    NSMutableArray *array = [[NSMutableArray alloc] init];
    self.continentList = array;
    
    NSMutableArray *countryList = [[NSMutableArray alloc] init];
    Country *country = [[Country alloc] initWithCode:@"USA"
                                                name:@"United States"
                                           continent:@"North America"
                                          population:[[NSNumber alloc] initWithInt:989898]];
    [countryList addObject:country];
    country = [[Country alloc] initWithCode:@"CAN"
                                       name:@"Canada"
                                  continent:@"North America"
                                 population:[[NSNumber alloc] initWithInt:979797]];
    [countryList addObject:country];
    country = [[Country alloc] initWithCode:@"MXN"
                                       name:@"Mexico"
                                  continent:@"North America"
                                 population:[[NSNumber alloc] initWithInt:969696]];
    [countryList addObject:country];
    
    Continent *continent = [[Continent alloc] init];
    continent.name = @"North America";
    continent.countryList = countryList;
    [self.continentList addObject:continent];
    
    countryList = [[NSMutableArray alloc] init];
    country = [[Country alloc] initWithCode:@"CHN"
                                       name:@"China"
                                  continent:@"Asia"
                                 population:[[NSNumber alloc] initWithInt:959595]];
    [countryList addObject:country];
    country = [[Country alloc] initWithCode:@"AFG"
                                       name:@"Afghanistan"
                                  continent:@"Asia"
                                 population:[[NSNumber alloc] initWithInt:939393]];
    [countryList addObject:country];
    
    continent = [[Continent alloc] init];
    continent.name = @"Asia";
    continent.countryList = countryList;
    [self.continentList addObject:continent];
    
}

- (void)viewDidLoad
{
    [super viewDidLoad];
 
    //set the background color
    self.view.backgroundColor = [UIColor whiteColor];
    
    //create the table view with a given style
    self.myTableView = [[UITableView alloc] initWithFrame:self.view.bounds
                                                    style:UITableViewStyleGrouped];
    
    //set the table view delegate to the current so we can listen for events
    self.myTableView.delegate = self;
    //set the datasource for the table view to the current object
    self.myTableView.dataSource = self;
    
    //make sure our table view resizes correctly
    self.myTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth |
                                                UIViewAutoresizingFlexibleHeight;
    
    //add the table view to the main view
    [self.view addSubview:self.myTableView];
    
    
}

//asks the data source to return the number of sections in the table view
//we are retuneing the number of continents
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    
    NSLog(@"%@",@"Called number of Sections in Table View");
    NSInteger numberOfSections = 0;
    
    if ([tableView isEqual:self.myTableView]){
        numberOfSections = self.continentList.count;
    }
    return numberOfSections;
}

//asks the data source to return the number of rows in a given section of a table view
//we are returning the number of countries in a given continent
- (NSInteger)tableView:(UITableView *)tableView
 numberOfRowsInSection:(NSInteger)section{
    
    NSLog(@"%@",@"Called number of Rows in a Section");
    NSInteger numberOfRows = 0;
    
    if ([tableView isEqual:self.myTableView]){
        
        Continent *continent = [[Continent alloc] init];
        continent = [self.continentList objectAtIndex:section];
        numberOfRows = continent.countryList.count;
        
    }
    return numberOfRows;
}


//asks the data source for a cell to insert in a particular location of the table view
- (UITableViewCell *) tableView:(UITableView *)tableView
          cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    NSLog(@"%@",@"Render cell at a given Index Path Section and Row");
    UITableViewCell *myCellView = nil;
    
    if ([tableView isEqual:self.myTableView]){
        
        static NSString *TableViewCellIdentifier = @"MyCells";
        
        //this method dequeues an existing cell if one is available or creates a new one
        //if no cell is available for reuse, this method returns nil
        myCellView = [tableView dequeueReusableCellWithIdentifier:TableViewCellIdentifier];
        if (myCellView == nil){
            //create a new cell
            myCellView = [[UITableViewCell alloc]
                      initWithStyle:UITableViewCellStyleDefault
                      reuseIdentifier:TableViewCellIdentifier];
        }
        
        //get the continent based on the index path section
        Continent *continent = [[Continent alloc] init];
        continent = [self.continentList objectAtIndex:indexPath.section];
        
        //get the country to display based on the index path row
        NSMutableArray *countryList = [[NSMutableArray alloc] init];
        countryList = continent.countryList;
        Country *country = [[Country alloc] init];
        country = [countryList objectAtIndex:indexPath.row];
        
        //display the country name in main label of the cell
        myCellView.textLabel.text = [NSString stringWithFormat:@"%@",
                                 country.name];
        
        //set the accessory view to be a clickable button
        myCellView.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
        
    }
    return myCellView;
}

//asks the delegate for the height to use for a row in a specified location
- (CGFloat) tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    NSLog(@"%@",@"Set the row height");
    CGFloat result = 20.0f;
    if ([tableView isEqual:self.myTableView]){
        result = 45.0f;
    }
    return result;
    
}

//Asks the delegate for a view object to display in the header of the specified
//section of the table view, display the continent name in the header view
- (UIView *) tableView:(UITableView *)tableView
viewForHeaderInSection:(NSInteger)section{
    
    UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, 30)];
    headerView.backgroundColor = [UIColor clearColor];
    Continent *continent = [[Continent alloc] init];
    continent = [self.continentList objectAtIndex:section];

    if ([tableView isEqual:self.myTableView]){
        UILabel *result = [[UILabel alloc]
                           initWithFrame:CGRectMake(12, 0, tableView.bounds.size.width, 30)];
        result.font = [UIFont boldSystemFontOfSize:16.0f];
        result.text = [NSString stringWithFormat:@"%@ :", continent.name];
        result.backgroundColor = [UIColor clearColor];
        [headerView addSubview:result];
    }
    return headerView;
    
}

//asks the delegate for a view object to display in the footer of the specified
//section of the table view
- (UIView *) tableView:(UITableView *)tableView
viewForFooterInSection:(NSInteger)section{
    
    UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, 30)];
    footerView.backgroundColor = [UIColor clearColor];
    
    if ([tableView isEqual:self.myTableView]){
        UILabel *result = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, 30)];
        result.font = [UIFont boldSystemFontOfSize:12.0f];
        result.text = [NSString stringWithFormat:@"Section %d Footer",
                       section];
        result.textAlignment =  NSTextAlignmentCenter;
        result.backgroundColor = [UIColor clearColor];
        [footerView addSubview:result];
    }
    return footerView;
    
}

//asks the delegate for the height to use for the header of a particular section
- (CGFloat) tableView:(UITableView *)tableView
heightForHeaderInSection:(NSInteger)section{
    
    CGFloat result = 0.0f;
    if ([tableView isEqual:self.myTableView]){
        result = 25.0f;
    }
    return result;
}

//asks the delegate for the height to use for the footer of a particular section
- (CGFloat) tableView:(UITableView *)tableView
heightForFooterInSection:(NSInteger)section{
    
    CGFloat result = 0.0f;
    if ([tableView isEqual:self.myTableView]){
        result = 20.0f;
    }
    return result;
}

//informs the delegate that the specified row is now selected
- (void) tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    
    if ([tableView isEqual:self.myTableView]){
        NSLog(@"%@",
              [NSString stringWithFormat:@"Cell %ld in Section %ld is selected",
               (long)indexPath.row, (long)indexPath.section]);
        Country *country = [self getCountryName:indexPath];
        NSLog(@"%@",
              [NSString stringWithFormat:@"Country is %@ and code is %@", country.name, country.code]);
        
    }
}

//informs the delegate that the user tapped the accessory view associated with a given row
- (void) tableView:(UITableView *)tableView
accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath{
    
    if ([tableView isEqual:self.myTableView]){
        NSLog(@"%@",
              [NSString stringWithFormat:@"Cell %ld accessory button in Section %ld is tapped",
               (long)indexPath.row, (long)indexPath.section]);
        Country *country = [self getCountryName:indexPath];
        NSLog(@"%@",
              [NSString stringWithFormat:@"Country is %@ and code is %@", country.name, country.code]);
        
        //if the detail view controller doesn't exists create it
        if(self.detailViewController == nil){
            CountryDetailViewController *detailView = [[CountryDetailViewController alloc] init];
            self.detailViewController = detailView;
        }
        
        //set the country object of the second view controller
        [self.detailViewController setCountry:country];
        
        //tell the navigation controller to push a new view into the stack
        [self.navigationController pushViewController:self.detailViewController animated:YES];
    }
}

//find the country based on a given index path
- (Country *) getCountryName:(NSIndexPath *)indexPath {
    
    Continent *continent = [[Continent alloc] init];
    continent = [self.continentList objectAtIndex:indexPath.section];
    NSMutableArray *countryList = [[NSMutableArray alloc] init];
    countryList = continent.countryList;
    Country *country = [[Country alloc] init];
    country = [countryList objectAtIndex:indexPath.row];
    return country;
    
}

- (void) didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

Interface file for Detail View Controller - CountryDetailViewController.h

#import <UIKit/UIKit.h>
#import "Country.h"

@interface CountryDetailViewController : UIViewController

@property (nonatomic, strong) Country *country;

@property (nonatomic, strong) UILabel *countryCode, *continentName, *population;

@end

Implementation file for Detail View Controller - CountryDetailViewController.m

#import "CountryDetailViewController.h"

@interface CountryDetailViewController ()

@end

@implementation CountryDetailViewController

@synthesize country;
@synthesize countryCode, continentName, population;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
 NSLog(@"%@",@"Country Detail View is Loading");
    
    [self.view setBackgroundColor:[UIColor whiteColor]];
    
    self.countryCode = [[UILabel alloc] init];
    [self.countryCode setFrame:CGRectMake(10.0,10.0,250.0,30.0)];
    [self.view addSubview: self.countryCode];
    
    self.continentName = [[UILabel alloc] init];
    [self.continentName setFrame:CGRectMake(10.0,40.0,250.0,30.0)];
    [self.view addSubview: self.continentName];
    
    self.population = [[UILabel alloc] init];
    [self.population setFrame:CGRectMake(10.0,70.0,250.0,30.0)];
    [self.view addSubview: self.population];
    
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:YES];
    
    [self.navigationItem setTitle:self.country.name];
    [self.countryCode setText:[NSString stringWithFormat:@"Country code is %@ ",
                               country.code]];
    [self.continentName setText:[NSString stringWithFormat:@"in continent %@ ",
                                 country.continent]];
    [self.population setText:[NSString stringWithFormat:@"has population of %@ ",
                              country.population]];
    
}


- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

Interface file for Table View App Delegate - TableViewExampleAppDelegate.h

#import <UIKit/UIKit.h>
#import "CountryViewController.h"

@interface TableViewExampleAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (nonatomic, retain) UINavigationController    *myNavigationController;
@property (nonatomic, retain) CountryViewController       *countryViewController;

@end

Implementation file for Table View App Delegate - TableViewExampleAppDelegate.m

#import "TableViewExampleAppDelegate.h"


@implementation TableViewExampleAppDelegate

@synthesize myNavigationController;
@synthesize countryViewController;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    
    //create the navigation controller and add to the view
    myNavigationController = [[UINavigationController alloc] init];
    [self.window addSubview:[self.myNavigationController view]];
    
    //check if the first viewcontroller eixsts, otherwise create it
    if(self.countryViewController == nil)
    {
        CountryViewController *countryView = [[CountryViewController alloc] init];
        self.countryViewController = countryView;
    }
    
    //push the first viewcontroller into the navigation viewcontroller stack
    [self.myNavigationController pushViewController:self.countryViewController animated:YES];

    
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application
{
    //do nothing
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    //do nothing
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    //do nothing
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    //do nothing
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    //do nothing
}

@end

Reference