iOS programmatically create a custom UITableViewCell

In our previous tutorial we learned how to create a custom UITableViewCell using a xib file. My personal preference is to define it programmatically as it takes me less time to code. In this example we basically recreate the same custom table cell view which displays our country information and a button that can be used to further drill down to say a detail screen about that specific country.

iOS programmatically create a custom UITableViewCell iOS custom UITableViewCell xcode project

Interface file for the 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 the 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 the app delegate - TableViewCustomCellAppDelegate.h

#import <UIKit/UIKit.h>

@class TableViewCustomCellViewController;

@interface TableViewCustomCellAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@property (strong, nonatomic) TableViewCustomCellViewController *viewController;

@end

Implementation file for the app delegate - TableViewCustomCellAppDelegate.m

#import "TableViewCustomCellAppDelegate.h"

#import "TableViewCustomCellViewController.h"

@implementation TableViewCustomCellAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //initialize the screen
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    
    //initialize your view controller
    self.viewController = [[TableViewCustomCellViewController alloc]            initWithNibName:@"TableViewCustomCellViewController" bundle:nil];
    
    //make the new view controller as your root view controller
    self.window.rootViewController = self.viewController;
    //set background color and make your window visible
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;

}

@end

Interface file for the Table view - TableViewCustomCellViewController.h

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

@interface TableViewCustomCellViewController : UIViewController
                                                <UITableViewDelegate,UITableViewDataSource>

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

@end

Implementation file for the Table view - TableViewCustomCellViewController.m

//
//  TableViewCustomCellViewController.m
//  TableViewCustomCell
//
//  Created by Developer on 6/10/13.
//  Copyright (c) 2013 MySampleCode. All rights reserved.
//

#import "TableViewCustomCellViewController.h"

#define COUNTRY_TAG 1
#define CODE_TAG 2
#define CONTINENT_TAG 3
#define POPULATION_TAG 4

@interface TableViewCustomCellViewController ()

@end

@implementation TableViewCustomCellViewController

@synthesize myTableView;
@synthesize countryList;

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    
    //intialize our data to be displayed in the table view
    [self loadCountryData];
    
    //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 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];
    
    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:@"%@ :", @"List of Countries"];
        result.backgroundColor = [UIColor clearColor];
        [headerView addSubview:result];
    }
    return headerView;
    
}

//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 = 35.0f;
    }
    return result;
}


//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]){
        numberOfRows = self.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;
    UILabel *countryLabel, *codeLabel, *continentLabel, *populationLabel;
    UIButton *detailInfoButton;

    if ([tableView isEqual:self.myTableView]){
        
        static NSString *TableViewCellIdentifier = @"CountryCell";
        
        //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){
            myCellView = [[UITableViewCell alloc]
                          initWithStyle:UITableViewCellStyleDefault
                          reuseIdentifier:TableViewCellIdentifier];
            
            //create custom labels and button inside the cell view
            CGRect myFrame = CGRectMake(10.0, 0.0, 220, 25.0);
            countryLabel = [[UILabel alloc] initWithFrame:myFrame];
            countryLabel.tag = COUNTRY_TAG;
            countryLabel.font = [UIFont boldSystemFontOfSize:17.0];
            countryLabel.backgroundColor = [UIColor clearColor];
            [myCellView.contentView addSubview:countryLabel];
            
            detailInfoButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
            detailInfoButton.frame = CGRectMake(200.0, 5.0, 90, 25.0);
            [detailInfoButton setTitle:@"Detail Info"
                           forState:UIControlStateNormal];
            [detailInfoButton addTarget:self
                              action:@selector(detailInfo:)
                    forControlEvents:UIControlEventTouchUpInside];
            [myCellView.contentView addSubview:detailInfoButton];

            myFrame.origin.y += 25;
            codeLabel = [[UILabel alloc] initWithFrame:myFrame];
            codeLabel.tag = CODE_TAG;
            codeLabel.font = [UIFont systemFontOfSize:17.0];
            codeLabel.backgroundColor = [UIColor clearColor];
            [myCellView.contentView addSubview:codeLabel];
            
            myFrame.origin.y += 25;
            continentLabel = [[UILabel alloc] initWithFrame:myFrame];
            continentLabel.tag = CONTINENT_TAG;
            continentLabel.font = [UIFont systemFontOfSize:17.0];
            continentLabel.backgroundColor = [UIColor clearColor];
            [myCellView.contentView addSubview:continentLabel];
            
            myFrame.origin.y += 25;
            populationLabel = [[UILabel alloc] initWithFrame:myFrame];
            populationLabel.tag = POPULATION_TAG;
            populationLabel.font = [UIFont systemFontOfSize:17.0];
            populationLabel.backgroundColor = [UIColor clearColor];
            [myCellView.contentView addSubview:populationLabel];
            
        }
        else {
            countryLabel = (UILabel *)[myCellView.contentView viewWithTag:COUNTRY_TAG];
            codeLabel = (UILabel *)[myCellView.contentView viewWithTag:CODE_TAG];
            continentLabel = (UILabel *)[myCellView.contentView viewWithTag:CONTINENT_TAG];
            populationLabel = (UILabel *)[myCellView.contentView viewWithTag:POPULATION_TAG];
        }
        
        Country *country = [[Country alloc] init];
        country = [self.countryList objectAtIndex:indexPath.row];
        
        //populate data from your country object to table view cell
        countryLabel.text = [NSString stringWithFormat:@"Name: %@", country.name];
        codeLabel.text = [NSString stringWithFormat:@"Code: %@", country.code];
        continentLabel.text = [NSString stringWithFormat:@"Continent: %@", country.continent];
        populationLabel.text = [NSString stringWithFormat:@"Population: %@", country.population];
        
        
    }
    return myCellView;
}

- (void) detailInfo:(UIButton *)sender {
    
    UITableViewCell *ownerCell = (UITableViewCell *)[[sender superview] superview];
    NSIndexPath *indexPath = [self.myTableView indexPathForCell:ownerCell];
    
    Country *country = [[Country alloc] init];
    country = [self.countryList objectAtIndex:indexPath.row];
    NSLog(@"Country is %i %@", indexPath.row, country.name);
    
}

- (CGFloat) tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    CGFloat result = 20.0f;
    if ([tableView isEqual:self.myTableView]){
        result = 100.0f;
    }
    return result;
    
}


//create mutable array to hold list of countries that will be displayed
- (void) loadCountryData {
    
    NSMutableArray *array = [[NSMutableArray alloc] init];
    self.countryList = array;
    
    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];
    
    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];
    
}


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

@end