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.
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!
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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!