2015-02-17

In an early post on this site, I wrote a table view tutorial. I decided to update that tutorial a bit for my upcoming book and add a bit more sophistication and depth. Both will remain on the site.

Basics of Table Views

The workhorse control in iOS is the table view. With both a delegate and data source it is powerful and flexible but far from simple. Table views have many uses. They can provide navigation much like a Tab bar. Tab bars use them in the more tab. They work very well for selection and listing of long amounts of data, as they are scrollable. As the basic unit of a table view, a cell is a view itself. As a subclass of UIView, cells customize easily.

Rows and Sections

All table views have rows and sections. For example, here is a table view with three sections: Pizza, Deep Dish Pizza and Calzone



Sections here have their own headers. Under the headers are rows. For Deep Dish Pizza, we have several types of pizza, such as Sausage, Meat Lover’s, Veggie Lover’s and so on. The developer has control over the way rows and sections set up.

Static and Dynamic Tables

There are two types of Table views: Static and dynamic. Static tableviews have a specific number of table sections and a specific number of rows in each section set at design time. They are easy to set in the storyboard. As table row cells are views, you can place any control you want in a cell and format using Auto layout. You can find a good example of a static table in any settings page like the one on the right. Static tables also make a way to perform navigation using Navigation controllers much like tab views.

Dynamic tables generate the table from data, and can change during run time. The pizza menu to the left  is a dynamic table, generated by an array for the sections and an array of arrays for the rows.  It can even generate its own background for each cell. Once you understand basic table views, you can edit the table view dynamically at run time, adding, removing and recording the data in the table. There are many apps that are complicated Dynamic table views. Social media apps like Facebook, Twitter and Instagram are dynamic table views with sophisticated layouts.

Set Up the Application.

We will build part of a menu application to demonstrate both static and dynamic tables. Start by making a new project with Command-Shift-N or File>New>Project… Name the project SwiftTableViewDemo. Set the device to Universal and the language to Swift.

Table View and Navigation Controller

Go to the storyboard. Delete the current view controller on the storyboard. Drag a Table View Controller out onto the storyboard.

Select the new table view controller on the storyboard. In the properties inspector, click on Is Initial View Controller. From the drop-down menu select Edit>Embed in>Navigation Controller. The story board should look like this.

In the navigation bar, drag a bar button item into the upper right corner. Title it Order. This button will launch the table view. Our root view will show our pizza and dessert order after we get it. We will code this view last.

Press Command-N for a new file. Select a Cocoa Touch Class which subclasses UITableViewController named RootTableViewController. Use Swift as the language. Save the file. There will be a lot of commented out code here. In its current state the code will run, but do nothing.

Go back to the storyboard. Select the table view and in the identity inspector, change the class to RootTableViewController.

We need to make two changes to the table view in the attributes inspector. You may find table views are difficult to select views on the storyboard. Use the document outline. If not already open, click the button in the lower right of the storyboard to open the document outline. In the outline find the Root Table Controller.

Open up the arrow next to the root controller then the table view.

Click the Table View Cell. In the properties inspector, set the Style to Basic, and the Identifier to Cell.

Adding the Static Table View

Drag a table view controller to the right of the view controller. Control drag from the order button to the Table View Controller to make a segue. Select a show segue. Click the segue and give it an identifier of Order in the properties inspector.

Get a new file by pressing Command-N. select Cocoa Touch Class subclassing UIViewController. Name the file FullMenuViewController. Use Swift as the language . Save the file. We did not use the UITableViewController for a subclass to get a less cluttered class To work as a table view controller, Change the superclass to UITableViewController.

Go back to the storyboard. Click the view controller icon. In the identity inspector, change the class to FullMenuViewController.

Control-Drag the order bar button from RootViewController scene to the FullMenuViewController scene. Select a segue of show. Select the segue and in the property inspector add a Segue identifier of Order.

In the document outline, click the Table View for the FullMenuViewController. In the property inspector, change the content to Static Cells.

The table will now change from Prototype content to static cells, and have a different arrangement.

Change the sections to 2, and you will get two sections with headers.

In the document outline, Select Section-1.

In the properties inspector, change the Header to Pizza. Select Section-2. In the properties inspector change the Header to Dessert. Change the Rows for the table view section to 2.

We have configured the table to have two sections. The first section will have three cells. The second section, the dessert section, will have two cells.

Open up Pizza in the document outline, and there will be three table view cells. Select the top Table View Cell in the document outline.

Change the style to Basic in the properties inspector. The storyboard will now have the word Title on it. Double click directly on the word, and you will be able to edit it. Change it to Pizza. In non-custom layouts, there is one or two system labels applied to the table view cell. We can change those labels like any other label.

Now do the same for the two other table view cells in the Pizza section. Add the titles Deep Dish Pizza and Calzone to the labels. Do the same for the Dessert cells, adding Pie and Ice Cream. Your table view should look like this:

Add a bar button for saving our order. After your first table controller, navigation bars do not get included in the controller on the story board. You need to add them yourself. If you don’t, you will not be able to drag a bar button to the upper right corner. Start by dragging a Navigation Item to the gray area for the navigation bar. In the attributes inspector, set the title to Full Menu. Now you can drag a bar button item to the upper corner. Set the identifier to Save.

Adding the Dynamic Table View

Drag another table view onto the storyboard. A dynamic table view appears by default. Drag the new table view controller to the right of the full menu view controller.

We’ll make one view controller, and hook up the three pizzas to it. Control-drag from the Pizza cell to the new table view. Make a show segue. Make a segue identifier named Pizza. Control-drag from the Deep Dish Pizza cell to the new table view. Make a show segue. Make a segue identifier named Deep Dish. Control-drag from the Calzone cell to the new table view. Make a show segue. Make a segue identifier named Calzone.

There is only one cell for the prototype cell. Select the cell in the document outline. Again change the style to Basic. Under the style, you will find an identifier. change the identifier to cell.

This is the reuse identifier. When we code cell contents, we will use this to identify the cell. You may have more than one kind of cell. This is a way of keeping them organized.

Build and run and you will be able to navigate from the order button to the order view, and from the pizzas to the blank table view controller.

Building the Models

Before we start coding the table view controllers, we need to make not just one but two models. We will need the model that will carry our order, and a class that will define the list that goes into the table view.

The Order Model

Press Command-N and make a new Cocoa Touch Class named OrderModel with Swift. Subclass it to NSObject. Change the class that appears to this:

The model is two strings, which initialize as the string None.

The Table View’s Model

Single arrays often describe the table view for single section tables. In multiple section tables, there is more than one array. In our case, we will make a three section table for the three different kinds of pizza. Press Command-N and make a new Cocoa Touch Class named MenuItems with Swift as a the language. Subclass it to NSObject. Change the class that appears to this:

The MenuItems class is very abstract. Our table view will require a array for the names of the sections and another array of the same size as the sections array. In that array we will stick arrays as elements which are the sections. This array of arrays will reference every section and every row in that section. The property sections is the string array containing the names of the sections. The property items is an array of string arrays, hence the double brackets for [[String]].

We add a section of the menu table by the method addSection, which adds the section and the item array to the existing property.

We could use this class one of two ways. We could make an instance of MenuItems within the view controller and then use the addSection method on the instance. That is a lot of code and data in a view controller. I can only use it in that view controller. A more flexible approach is subclassing MenuItems. Under the MenuItems class, add this.

I subclass MenuItems with PizzaMenuItems.  I override the initializer adding the three sections of pizza. Now I make an instance of PizzaMenuItems whenever I need this list.

Code the Dynamic Table View

We next code the table view controller. We did subclass TableViewController for the RootTableViewController, but like many Apple templates, it has a lot of confusing extra code sitting in comments. To simplify things and to illustrate more effectively what you do need get a table view controller working, we will subclass UIViewController and then make a few changes.

Make the File

Type Command-N to make a new file. Make a Cocoa Touch Class called PizzaMenuViewController subclassing UIViewController and using Swift. Delete everything in the class except viewDidLoad. Change the superclass from UIViewController to UITableViewController. Your class should look like this:

Add the two models as properties under the class definition:

Set the Data Source

All table views require two data source methods. They return to the Table View how many sections and how many rows in each section. Add the following to your code:

This returns the count of the number of sections.

The second required method is a count of rows in each section. The numberOfRowsInSection method has a parameter of section. We count the array of items for the current section. Add this to the code:

Configure The Cells

Add this method:

The parameters for this method are the tableView, and a NSIndexPath called indexPath. NSIndexPath has two properties of interest: section and row. Line 1 instantiates a cell. Since dequeueReusableCellWithIdentifier returns AnyObject, we must downcast to UIViewCell, which is the class of a table cell.

Once we have a cell, we configure it. With the Basic style, there is one item to configure. textLabel is a UILabel found in the cell. We assign to the text property of textLabel the name of the pizza. We get that from the array of the array, using indexPath as our reference point.

Go to the story board and select the new table view. In the identity inspector, set the class to PizzaMenuViewController. Build and run. Tap order and then tap a pizza button. You will see the new table:

Adding Basic Headers

The table shows all of the data.  We can’t tell in what section each pizza appears. If we displayed section names, this would be much clearer. There are several methods for displaying section information. One of the most common is tableview:TitleForRowInSection . Add this to your PizzaMenuViewController code:

This method returns a string which is a title for a header row. We use our menuItems.sections array to give a title.

Build and run. We now have sections which make the pizza sections clear. Scroll down the list to see a few calzones:

Selecting a Cell

While this all looks nice, it does nothing. We need to select a menu item. There is another delegate method tableView:didSelectRowAtIndexPath to do this. Add this to your PizzaTableViewController class:

In this method, we have  indexPath for a parameter. Rows two and three create constants that make working with these values a little easier. Line 4 gets data from our menuItem object, much like we did in cellForRowAtIndexPath and titleForRowInSection. I created a string order detailing the ordered pizza. To show feedback, I placed order  in the title of the navigation controller bar.

Build and run . Scroll down the table view and select a Chicken Pesto Calzone

We have two forms of feedback right now. First we have the title, and we also have the selected item highlighted. To show only the title, deselect the item once posted. Add this to the bottom of the didSelectRowAtIndexPath method:

Build and run. Now the tapped row flashes, but does not stay solid. This gives feedback we tapped the button, but does not stay on. If you want all your user feedback to be the label on top, you can set animated: to false.

Adding Delegates

Like any other Navigation controller, we delegate the data back to the root controller. To get back to the root and display our selection, we pass the model through the full menu we made.

A Delegate File

We will use the same delegate several times in different view controllers. In previous chapters, we placed the protocol for the delegate in the same file as the view controller. This time we will make a separate file. It will help with documenting the protocol.

Make a new file with Command- N. Make a Cocoa Touch Class in Swift named MenuItemSelectionDelegate, subclassing NSObject. Remove everything below the import UIKit. Add the following in its place:

That is our simple generic protocol, which passes the view controller and the model back to the calling controller.

Setting up the Delegate

Go to the PizzaMenuViewController . Add the delegate property:

In the cellForRowInIndexPath method, set the model and call the protocol:

Go to the FullMenuViewController. Adopt the protocol by adding the protocol to the class definition:

Add the model as a property:

Add the required method for the delegate. In this case we want to update the model in this view controller, then dismiss the calling view controller.

Since we lose feedback of what we selected in the pizza menu, we added a line to display the passed order as the navigation title.

Last step is to set up prepareForSegue. Add the following:

Since we have three segues, we define each segue. Build and Run. Select a Seafood Pizza. The menu changes to show the order:

The Order List Table

Dynamic table views change. User input can change them, adding cells as we do interactions. We will have the RootTableViewController list the items we order.This needs an array of OrderModel.

Make the Model

Press Command-N to make a new file. Make a Cocoa Touch Class in Swift subclassing NSObject. Name it OrderList.

Once saved change the class to this:

Go to the RootTableViewController. Add the model to the view controller:

Configure the Table View

Compared to the PizzaMenuViewController, there is a lot of code here. As I’ve mentioned, I tend to make my own TableViewController whenever I can.

Unlike the pizza menu we have only one section. Under the numberOfSectionsInTableView, is numberOfRowsInSection. Replace that code with this.

Like PizzaTableViewController, we count the elements in the array to return the number of rows in each section, though this time we have only one section.

Our last required method is under numberOfRowsInSection . Remove the block comments from cellForRowAtIndexPath and change the code there to this.

Be especially careful to make the identifier cell. It must match the identifier we set up in the storyboard.

The Model Delegate

Our last step is get the order from FullMenuViewController. Go to the storyboard and open the assistant editor set to automatic. Select the bar button in the FullMenuViewController scene. Control drag from the Save bar button to the code. Make a action for a UIBarButton called saveButton. In the code for saveButton, add a delegate method call:

Since we did not add a delegate yet, you will get an error. Add this property to the class:

Go back to the RootTableViewController and close the assistant editor. Adopt the delegate in the class definition:

Add the required method:

We add the order to the list, then dismiss the controller. Our last step is connect up via the FullMenuController segue. Uncomment the prepareForSegue and change it to this:

Build and run. Select a few menu times and save them. you will see the table grow on the root screen.

There is a lot we can do with table views. We will discuss several formatting options in next week’s lesson.

The Whole Code

RootTableViewController.swift

FullMenuViewController.swift

PizzaMenuViewController.swift

MenuItemSelectionDelegate.swift

MenuItems.swift

OrderModel.swift

OrderList.swift

Show more