Two Basic Ways To Populate Your UITableView

Published Apr 20, 2015Last updated Jan 18, 2017

There are two main base ways to populate a tableview. The more popular is through Interface Building, using a prototype cell UI object. The other is strictly through code when you don't need a prototype cell from Interface Builder.

Why One Versus The Other

Let's looks at why use the first method, which goes through Interface Builder. Adding the tableview cell (also called prototype cell) through Interface Builder will save you from typing some code, specifically needing to registerClass(). Interface Builder will handle this part for you.

You will need to tell Interface Builder the cell identifier you'll be using. This is the same identifier you'll use for dequeueing the cell in code, since dequeueing is done by cell name. Otherwise, Interface Builder will not know which cell you are referring to, which will cause a runtime exception, crashing your app.

On the other hand, you go use the second method, which does strictly in code. If your tableview cells are very simple and you don't need assistance from Interface Builder to design them, doing everything in code can be faster and simpler.

Creating The TableView With Interface Builder

The following is a simple method for getting a tableview into a scene. This starts with a new app. For this article, I'm going to start with a Single View Application.

enter image description here

We want to now delete the view. We'll replace it with a tableview. Click Main.storyboard and open the Document Outline (Editor > Show Document Outline). Click the View and press delete.

enter image description here

Once the view is gone, you'll see just the bare View Controller.

enter image description here

In the Object Library, type tableview and drag it onto the View Controller as shown below.

enter image description here

This will place the tableview on top of the View Controller. Your Document Outline will also look like the following:

enter image description here

Steps Involved When Using Interface Builder

This method starts with dragging a Table View Cell from the Object Library onto your TableView. The image below shows the final result:

enter image description here

To set the cell identifier, click the prototype cell then Identity Inspector and provide an identifier. Below, we've set it to customcell.

enter image description here

Datasource and Delegates

There are a couple of more things to do in Interface Builder. We need to connect up our tableview datasource and delegate. Otherwise, our table will not be able to load data or process the UITableViewDelegate protocol methods.

To connect the TableView, click the Connections Inspector and drag from the datasource to the Table View. Do the same for the delegate as show below.

enter image description here

Common Patterns For Both Methods Of Populating Your TableView

Because we started with a Single View Application, our main scene contains a UIViewController class. We'll need to change this to type UITableViewController.

class ViewController: UITableViewController

This is the simplest option for being ready to implement UITableView related methods. If you don't use this subclass, you'll have to manually add the datasource and delegate protocols, as shown below:

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate

Either way will provide the same end result.

Now we need to add some common functions to both methods of populating. First we need to set the number of rows to display. Type tableview and you should see an auto complete for the method numberOfRowsInSection. Hit the return key to accept this method. Now hit the tab key and type in return 3. We have now completed this method.

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 3
    }

We're going to grab the second required method. Type tableview again and you should get an auto complete for the method cellForRowAtIndexPath. Hit the return key to accept it. Tab to the word code, which should be highlight. Finish out the method with the following code:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
     let cell = tableView.dequeueReusableCellWithIdentifier("customcell", forIndexPath: indexPath) as! UITableViewCell
     cell.textLabel?.text = "test"
     return cell
    }

Let's talk about what's going on in this method. You can see we're dequeueing a cell using the identifier we plugged into Interface Builder. We also must cast this object to type UITableViewCell, since we can use a custom type (inheriting from UITableViewCell) if we want.

Notice the as! syntax in our cast. This is called forced failable. It means we are absolutely sure the type we are casting to is going to be that type.

Next we assign some text to the label of this cell. Since textLabel can contain nil, we use Optional syntax to access it. Otherwise, you'll get a runtime error. Finally, cellForRowAtIndexPath is expecting a UITableViewCell to be returned, which is what we do.

Assigning the Data

To get data into the Tableview, we're going use a simple array of Strings. Declare the following just above viewDidLoad():

let myarray = ["item1", "item2", "item3"]

We can now modify our delegate methods to use this array. Make the following modification to numberOfRowsInSection:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
     return myarray.count
    }

You can see we are now returning the array count rather than just a static number.

Now modify cellForRowAtIndexPath:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("customcell", forIndexPath: indexPath) as! UITableViewCell
        cell.textLabel?.text = myarray[indexPath.item]
        return cell
    }

Here we are assigning the string value of an array item to the cell text label.

If you run the app, you'll see the tableview is now populated.

Referencing the Tableview Object

Let's do one last thing that will allow us to access to the tableview object. This can be useful when we need to reload tableview data, which we might want to do when something is added to our array.

We create a reference in Interface Builder. Open the Assistant Editor and click the tableview. Control drag from the tableview to the ViewController class to create an IBOutlet, as shown below:

enter image description here

Type in tableview for the Outlet name and click Connect. You should see the following IBOutlet in the ViewController class:

@IBOutlet var tableview: UITableView!

A good place to reload tableview data is in viewDidAppear(). Under viewDidLoad(), start typing viewDidAppear. You should get an auto complete. Hit enter and then add the following code to this method:

override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        tableview.reloadData()
    }

When this particular view loads, it will repopulate tableview data. Although it doesn't really do anything in this simple demo, if you had another scene where users could add data, once they come back to the main scene with the tableview, the newly added data will display as the tableview reloads its data.

Populating A TableView Without Interface Builder

We're going to look at the second way to populate a tableview, which is without using Interface Builder. Sometimes you want this method if you have no need for a tableview cell UI element.

This means we'll be doing everything in code. We're going to use the same class from the first technique:

class ViewController: UITableViewController

Remember when we did the tableview datasource and delegate connections in Interface Builder? We still need to do those but we'll do them in viewDidLoad() this time. First, create the IBOutlet (as shown above) for your tableview. Then add the following to your viewDidLoad() method:

tableview.dataSource = self
tableview.delegate = self

We still need to supply a cell identifier name for our tableview cell that we will be dequeueing. In the first method, we did this in Interface Builder. In code, we need to call a method named registerClass. The following is what your viewDidLoad() method should now look like:

override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        tableview.dataSource = self
        tableview.delegate = self
        tableview.registerClass(UITableViewCell.self, forCellReuseIdentifier: "customcell")
        
    }

Above viewDidLoad(), declare the same array we used from the first technique:

let myarray = ["item1", "item2", "item3"]

It's time to add the two tableview delegate methods. We can just copy what we did in the first technique. Paste the following into your ViewController class:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return myarray.count
    }
    
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("customcell", forIndexPath: indexPath) as! UITableViewCell
        cell.textLabel?.text = myarray[indexPath.item]
        return cell
    }

That's it! You can now run the app to see the data loads into the tableview.

If you want, you can also add the table view reloadData() method to viewDidAppear(). This can be useful if you have another scene that users enter in data, which is saved to the array. Once they return to the main see, viewDidAppear() will trigger, kicking off the tableview reloadData() method.

Summary

We've just gone through two techniques for loading data into a tableview. One is using Interface Builder, which is a common approach. The other is strictly through code, which can be useful when you don't need any design assistance.

Discover and read more posts from Brett Romero
get started
Enjoy this post?

Leave a like and comment for Brett

4
2