4.0. Introduction

A table view is simply a scrolling view that is separated into sections, each of which is further separated into rows. Each row is an instance of the UITableViewCell class, and you can create custom table view rows by subclassing this class.

Using table views is an ideal way to present a list of items to users. You can embed images, text, and other objects into your table view cells; you can customize their height, shape, grouping, and much more. The simplicity of the structure of table views is what makes them highly customizable.

A table view can be fed with data using a table view data source, and you can receive various events and control the physical appearance of table views using a table view delegate object. These are defined, respectively, in the UITableViewDataSource and UITableViewDelegate protocols.

Although an instance of UITableView subclasses UIScrollView, table views can only scroll vertically. This is more a feature than a limitation. In this chapter, we will discuss the different ways of creating, managing, and customizing table views.

Table views can be utilized in two ways:

  • By using the UITableViewController class. This class is similar to the UIViewController class (see Recipe 1.9) in that it is a view controller, but representing a table instead of a normal view. The beauty of this class is that every instance of it already conforms to the UITableViewDelegate and the UITableViewDataSource protocols. So the table view controller by default becomes the data source and the delegate of the table view that it controls. Therefore, in order to implement a method of, for instance, the data source of the table view, all you have to do is implement it in the table view controller instead of having to set the data source of your table view manually to your view controller.

  • By instantiating the UITableView class manually.

Both these methods are valid methods of creating table views. The first method is usually used when you have a table view that fills its container (or the whole screen/window, if the table view controller is the root view controller of the main window of your app). The second method is usually used for situations where you want to display your table view as a smaller part of your UI, perhaps taking half the width and/or height of the screen. But nothing prevents you from using the second method and setting the width and height of your table view to the width and height of your container window, so that your table view fills the whole screen. We will explore both these methods in this chapter.

Let’s have a look at an example of creating a table view in our application. We are going to see an example of table view controllers in Recipe 4.9, so for now, we will simply focus on creating table views in code and adding them to an existing view controller.

The way to instantiate UITableView is through its initWithFrame:style: method. Let’s see what parameters we have to pass to this method and what those parameters mean:

initWithFrame

This is a parameter of type CGRect. This specifies where the table view has to be positioned in its superview. If you want your table view to simply cover your whole view, pass the value of the bounds property of your view controller’s view to this parameter.

style

This is a parameter of type UITableViewStyle that is defined in this way:

typedef NS_ENUM(NSInteger, UITableViewStyle) {
    UITableViewStylePlain,
    UITableViewStyleGrouped
};

Figure 4-1 shows the difference between a plain table view and a grouped table view.

We feed data to a table view using its data source, as we will see in Recipe 4.1. Table views also have delegates that receive various events from the table view. Delegate objects have to conform to the UITableViewDelegate protocol. There are some methods in this protocol that are quite important to know:

tableView:viewForHeaderInSection:

Gets called on the delegate when the table view wants to render the header view of a section. Each section of a table view can contain a header, some cells, and a footer. We will talk about all these in this chapter. The header and footer are simple instances of UIView. This method is optional, but if you want to configure a header for your table view sections, use this method to create that instance of the view and return it as the return value. To read more about headers and footers in table views, refer to Recipe 4.5.

Different types of table views

Figure 4-1. Different types of table views

tableView:viewForFooterInSection:

Same as the tableView:viewForHeaderInSection: delegate method, but returns the footer view. Like the header, the footer is optional but should be created here if you want one. To read more about headers and footers in table views, refer to Recipe 4.5.

tableView:didEndDisplayingCell:forRowAtIndexPath:

Gets called on your delegate object when a cell is scrolled off the screen. This is a really handy method to have called on our delegate because you can delete objects and remove them from memory, if those objects were associated with the cell that is scrolled off the screen and you expect that you may no longer need them.

tableView:willDisplayCell:forRowAtIndexPath:

This method is called on the delegate of a table view whenever a cell is about to be displayed on the screen.

You can set the delegate of a table view simply by setting the value of the delegate property of an instance of UITableView to an object that conforms to the UITableViewDelegate protocol. If your table view is part of a view controller, you can simply make your view controller the delegate of your table view, like so:

#import "ViewController.h"

@interface ViewController () <UITableViewDelegate>
@property (nonatomic, strong) UITableView *myTableView;
@end

@implementation ViewController

- (void)viewDidLoad{
    [super viewDidLoad];

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

    self.myTableView.delegate = self;

    [self.view addSubview:self.myTableView];

}

@end

Think of the delegate of a table view as an object that listens to various events sent by the table view, such as when a cell is selected or when the table view wants to figure out the height of each of its cells.

Note

It is mandatory for the delegate object to respond to messages that are marked as @required by the UITableViewDelegate protocol. Responding to other messages is optional, but the delegate must respond to any messages you want to affect the table view.

Messages sent to the delegate object of a table view carry a parameter that tells the delegate object which table view has fired that message in its delegate. This is very important to note because you might, under certain circumstances, require more than one table view to be placed on one object (usually a view). Because of this, it is highly recommended that you make your decisions based on which table view has actually sent that specific message to your delegate object, like so:

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

The location of a cell in a table view is represented by its index path. An index path is the combination of the section and the row index, where the section index is the zero-based index specifying which grouping or section each cell belongs to, and the cell index is the zero-based index of that particular cell in its section.

Get iOS 7 Programming Cookbook now with O’Reilly online learning.

O’Reilly members experience live online training, plus books, videos, and digital content from 200+ publishers.