4.3. Populating a Table View with Data

Problem

You would like to populate your table view with data.

Solution

Conform to the UITableViewDataSource protocol in an object and assign that object to the dataSource property of a table view.

Discussion

Create an object that conforms to the UITableViewDataSource protocol and assign it to a table view instance. Then, by responding to the data source messages, provide information to your table view. For this example, let’s go ahead and declare the .h file of our view controller, which will later create a table view on its own view, in code:

#import <UIKit/UIKit.h>

@interface Populating_a_Table_View_with_DataViewController
           : UIViewController <UITableViewDataSource>

@property (nonatomic, strong) UITableView *myTableView;

@end

In the viewDidLoad method of our view controller, we will create the table view and will assign our view controller as its data source:

- (void)viewDidLoad{
  [super viewDidLoad];

  self.view.backgroundColor = [UIColor whiteColor];

  self.myTableView =
    [[UITableView alloc] initWithFrame:self.view.bounds
                                 style:UITableViewStylePlain];

  self.myTableView.dataSource = self;

  /* Make sure our table view resizes correctly */
  self.myTableView.autoresizingMask =
    UIViewAutoresizingFlexibleWidth |
    UIViewAutoresizingFlexibleHeight;

  [self.view addSubview:self.myTableView];

}

Now we need to make sure our table view responds to the @required methods of the UITableViewDataSource protocol. Hold down the Command key on your keyboard and click on the UITableViewDataSource protocol’s mention in your view controller’s .h file. This will show you the required methods for this protocol.

The UITableView class defines a property called dataSource. This is an untyped object that must conform to the UITableViewDataSource protocol. Every time a table view is refreshed and reloaded using the reloadData method, the table view will call various methods in its data source to find out about the data you intend to populate it with. A table view data source can implement three important methods, two of which are mandatory for every data source:

numberOfSectionsInTableView:

This method allows the data source to inform the table view of the number of sections that must be loaded into the table.

tableView:numberOfRowsInSection:

This method tells the view controller how many cells or rows have to be loaded for each section. The section number is passed to the data source in the numberOfRowsInSection parameter. The implementation of this method is mandatory in the data source object.

tableView:cellForRowAtIndexPath:

This method is responsible for returning instances of the UITableViewCell class as rows that have to be populated into the table view. The implementation of this method is mandatory in the data source object.

So let’s go ahead and implement these methods in our view controller, one by one. First, let’s tell the table view that we want it to render three sections:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{

  NSInteger result = 0;
  if ([tableView isEqual:self.myTableView]){
    result = 3;
  }
  return result;

}

Then we tell the table view how many rows we want it to render, for each section:

- (NSInteger)tableView:(UITableView *)tableView
 numberOfRowsInSection:(NSInteger)section{

  NSInteger result = 0;
  if ([tableView isEqual:self.myTableView]){
    switch (section){
      case 0:{
        result = 3;
        break;
      }
      case 1:{
        result = 5;
        break;
      }
      case 2:{
        result = 8;
        break;
      }
    }
  }
  return result;

}

So up to now, we have asked the table view to render three sections with three rows in the first, five rows in the second, and eight rows in the third section. What’s next? We have to return instances of UITableViewCell to the table view—the cells that we want the table view to render:

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

  UITableViewCell *result = nil;

  if ([tableView isEqual:self.myTableView]){

    static NSString *TableViewCellIdentifier = @"MyCells";

    result = [tableView
              dequeueReusableCellWithIdentifier:TableViewCellIdentifier];

    if (result == nil){
      result = [[UITableViewCell alloc]
                initWithStyle:UITableViewCellStyleDefault
                reuseIdentifier:TableViewCellIdentifier];
    }

    result.textLabel.text = [NSString stringWithFormat:@"Section %ld, Cell %ld",
                             (long)indexPath.section,
                             (long)indexPath.row];

  }

  return result;

}

Now if we run our app in iPhone Simulator, we will see the results of our work (Figure 4-2).

A plain table view with three sections

Figure 4-2. A plain table view with three sections

When a table view is reloaded or refreshed, it queries its data source through the UITableViewDataSource protocol, asking for various bits of information. Among the important methods previously mentioned, the table view will first ask for the number of sections. Each section is responsible for holding rows or cells. After the data source specifies the number of sections, the table view will ask for the number of rows that have to be loaded into each section. The data source gets the zero-based index of each section and, based on this, can decide how many cells have to be loaded into each section.

The table view, after determining the number of cells in the sections, will continue to ask the data source about the view that will represent each cell in each section. You can allocate instances of the UITableViewCell class and return them to the table view. There are, of course, properties that can be set for each cell, including the title, subtitle, and color of each cell, among other properties.

Get iOS 6 Programming Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.