UITableView tutorial using Swift 2.0

by Apr 23, 2016




Transcript – UITableView tutorial using Swift 2.0

What we’re going to learn

Hi everyone! In this video we’re going to look at the basic steps for getting a UITableView working in Swift 2.0 for our iOS apps. (show the version of Xcode, etc)

If you’re a beginner, you do not want to miss this video. Advanced viewers will also find this video interesting, because we will not be stuffing everything into our ViewController. If you’re advanced and want to skip the overview, the jump to the code discussion is listed in the comments. So let’s dive in!

Overview of UITableView

The table view on the iPhone or iPad is a UI control that displays a list of information. The default Settings app uses a table view.

The YouTube app uses an advanced table view with custom views for each cell. In fact, the UITableView is used in almost every iOS app. It’s that ubiquitous and it’s that important.

The table view is built from the following parts. The complete control is the table view. Every row in a table view is called a cell. The row cells hold one view of information. The rows are also grouped into sections, each with a section header. The sections group cells that are related logically. For example, a table view holding a list of countries might group them by continent. So Europe would contain a list of countries in Europe, Asia would contain Asian countries, and so on.

We can also have different cells in one table view, each rendered in our app in it’s own way. Every cell type is identified with a string called a reuse identifier. It’s very expensive to keep every row in our table in memory, so iOS only creates enough rows to fill the display. As one row scrolls offscreen, it’s replaced on the other end with another row. If it’s the same cell type, it just reuses the cell and changes the information to display.

Swift UITableViewDataSource

The UITableView is UI control only. It’s not supposed to hold data, and it doesn’t. The UITableView requires a source for the data it needs to display. Our data source must adopt the UITableViewDataSource protocol. This is an object we can ask questions like, “how many rows are there” or “what data is at row 42?”. In fact these are the two questions we must answer for every table view.

The UITableViewDataSource protocol requires that we implement the methods for numberOfRowsInSection and cellForRowAtIndexPath. numberOfRowsInSection simply returns a number that tells our table view how many items we have in the table. cellForRowAtIndexPath answers the question what data is at a particular index path.

An index path is a class representing the coordinates for data in our table. It contains the section number, and the row number. If our table has only one section, we can ignore the section number. The row number is the index of the row for a section, starting at one.

If our table has 2 sections each with four rows, the index path for India is like this. The index path for Germany looks like this.

Swift UITableViewDelegate

The UITableViewDelegate protocol handles table row configuration and selection, row reordering, highlighting, accessory views, and editing operations. We’re not going to use the delegate much in this tutorial. We’ll cover it more in another tutorial. We just want to get things running for this go around.

class MyTableViewDelegate: NSObject, UITableViewDelegate {

}

Where to put the datasource/delegate

Here’s where things get a bit interesting. Almost every tutorial you’ll find puts everything into the view controller. By that I mean, our view controller is also our table view data source and our table view delegate.

The view controller implements the UITableViewDataSource and UITableViewDelegate protocols. This makes for a very heavy weight view controller. For simple apps, it’s ok, but we really want to pull it out into specialized classes.

We could extract these protocols to an extension for our view controller. This works if our goal is only to make the view controller code smaller. I prefer to make the protocols into their own class, and that is what we are going to do. We are going to create classes separate from our view controller to represent our data and our table operations.

OK. Let’s dive into creating the code! The code is on GitHub if you want to follow along at home.

Steps to add a UITableView using Swift

The first thing we want to do is create a single view app. Call it what ever you want. Make sure the language is Swift. It should be the default. Save it somewhere on your machine.

This gives us our single view app. Next we want to go into our storyboard and delete the view controller. We don’t want it. We could use it, but I really don’t want to deal with the autolayout issues by creating our own table view controller from scratch. We’ll also delete the ViewController swift file. What we want is to create a table view controller instead. We will drag one out from the list in the object library. Make sure it’s the initial view controller. We can set that in the attributes inspector.

We’re only going to use one type of cell for this app. We still need to give the cell an identifier. So we’ll identify the cell as “cell”. All lowercase. If we had more cell types, we’d use more meaningful names for our cell types. We’ll set this cell style to “basic”.

Next we need a swift file to represent our TableViewController. To do this, we’ll add a cocoa touch class and create a TableViewController. When we’re creating a bigger app, we can be creative with the name, but here we’ll call it TableViewController.

We also need to connect this class to our storyboard controller, so we’ll go into the Identity inspector and connect the two by selecting the correct class. Find and set the class in the Custom class section.

For some reason, Apple encourages people to build these massive view controllers. As you can see in the swift file, there are all the methods needed for our delegate and datasource. We’re going to delete it all. We’re putting this code in separate classes.

Create table view delegate class

First we’ll create the delegate class. It looks like this. The class derives NSObject, and we implement the UITableViewDelegate protocol. There are no required methods to implement, so we are done with this class. We’ll do more with it in later tutorials.

Create table view datasource class

Next we create the datasource class. This class also derives from NSObject and implements the UITableViewDataSource protocol. We also need data. I’ve been meaning to start a “Happy Things” app, so we’ll start there with an array of things that make me happy. We also need to store the cell reuse identifier. We’ll store it here. We’ll set these elsewhere in our code.

Our datasource needs to answer two questions for our table view. How many, and what item is at a position. We have an array holding all our happy things, so answering how many is simply how many items are in the array. We’ll implement the required method numberOfRowsInSection to answer how many items, and we’ll return the array count.

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

Next we need to answer what happy thing is at a particular position in the array. We do that by implementing the cellForRowAtIndexPath method. The catch is this method returns a cell, not a string or anything. We need to first get a cell. This is where the reuse identifier comes in. We call dequeueReusableCellWithIdentifier, and pass the cell identifier we want. This will do one of two things. It will return a new cell, or it will return a cell already created but not currently in use.

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        
    let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as UITableViewCell
        
    // Fetch Happy Item
    let item = happyThings[indexPath.row]
        
    // Configure Cell
    cell.textLabel?.text = (item as! String)
    return cell
}

Once we have the cell, we take a look at the index path to see which item we need to use to populate our cell. The index path has a row attribute and a section attribute. We only have one section, so we’ll ignore the section attribute for now. We’ll use the row attribute to find the correct happy thing in our array. We set the cell text to the array item, and we’re done. We return the cell.

Let’s also implement one optional method from the protocol for headers. We’ll organize our happy things in a section called “Happy Things”. The method we need to implement is titleForHeaderInSection, and it returns a string for a given section. We have one section, so we’ll simply return the string “Happy Things”.

At this point we have all the code in place. We need to go back to our TableViewController class and connect everything up. First we need a list of happy things to pass in an array. Here’s my list of things that make me happy. We will pass the reuse identifier we used earlier in our storyboard. To connect everything, we need to tell our tableview what class is used for the delegate and data source. And that’s it.

class TableViewController: UITableViewController {
    let myDataSource = MyTableViewDataSource(happyThings: ["Beer", "Free candy", "YouTube subscribers", "Programming"], cellIdentifier: "cell")
    let myDelegate = MyTableViewDelegate()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Set the tableview datasource
        self.tableView.dataSource = myDataSource
        self.tableView.delegate = myDelegate
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

We’ll run the app, and we should see the list of happy things listed in a table view.

What happens when the tableview doesn’t draw

So what happens if the table view doesn’t draw. There’s a few things you can check.

TableViewController class

Make sure you’ve set the table view controller class in the Identity inspector. The code in our class won’t get called if you forget this.

Verify datasource and delegates

Make sure the datasource and delegate are set correctly. If you haven’t set these, the tableview won’t know where to get data, or how it should behave.

Make sure the cell identifier is the same in all places

The cell reuse identifier needs to be the same in all places. Usually this is one place in our code, and once in the storyboard. If these identifiers do not match exactly, the table view will not work.

Make sure the row height is greater than zero

If we’ve created our table cells instead of using the defaults, we need to make sure we’ve defined the size appropriately. If the height is zero or the frame is undefined, cellForRowAtIndexPath will never get called. If cellForRowAtIndexPath doesn’t get called, our table will always be empty.

Where you declare datasource array matters – not Java

This is a weird one, but if we’re coming from a Java background it can trip us up. In the datasource, we’re creating our array at the class level. If it’s created in the method, a Java developer will expect the array to survive past the method scope. This doesn’t happen in Swift. The array is method local. When we run the app, the tableview will not display. That’s why we created the array at the class level.

Clean your build in Xcode

Finally, if we’ve made a change and we suspect everything should be correct, clean your build. This will ensure everything is compiled fresh, and includes everything to date.

Conclusion

Wow. Another big tutorial to accomplish something simple. The source code is up on Github, so you’ll want to look over it.

If you have any questions let me know in the comments. New videos are out every week, so make sure you subscribe. This puts new videos in your YouTube feed. I also have an newsletter on DeegeU.com. I’ll send this out once every month with links to the month’s videos and any other tips and tricks not on YouTube. The newsletter list is not shared or sold, so you’ll only get an email once a month from me.

And with that, I’ll see you in the next tutorial!







Related Posts

Tools Used

  • Swift 2.2
  • iOS 9.3
  • Xcode 7.3

Media Credits

All media created and owned by DJ Spiess unless listed below.

  • No infringement intended

Hackbeat by Kevin MacLeod is licensed under a Creative Commons Attribution license (https://creativecommons.org/licenses/by/4.0/)
Source: http://incompetech.com/music/royalty-free/index.html?isrc=USUAN1100805
Artist: http://incompetech.com/

Get the code

The source code for “UITableView tutorial using Swift 2.0” can be found on Github. If you have Git installed on your system, you can clone the repository by issuing the following command:

 git clone https://github.com/deege/deegeu-ios-swift-tableview-simple.git

Go to the Support > Getting the Code page for more help.

If you find any errors in the code, feel free to let me know or issue a pull request in Git.

Don’t miss another video!

New videos come out every week. Make sure you subscribe!

Comments

comments

DJ Spiess

DJ Spiess

Your personal instructor

My name is DJ Spiess and I’m a developer with a Masters degree in Computer Science working in Colorado, USA. I primarily work with Java server applications. I started programming as a kid in the 1980s, and I’ve programmed professionally since 1996. My main focus are REST APIs, large-scale data, and mobile development. The last six years I’ve worked on large National Science Foundation projects. You can read more about my development experience on my LinkedIn account.

Pin It on Pinterest

Share This