In the previous section, we set up our table view controller to display some sample data. Next, we're going to update our UITableViewCell UI by building a custom table view cell.

When we're done, each cell will display's the note's title and last modified timestamp.

Setting a Custom Row Height

Before we create our custom cell, let's adjust the row height for each cell in our table view. This will make the cell height of each of the table view cells taller.

By default, each row, or cell, in a UITableView will have a row height of 44pts.

In Main.storyboard, increase the table view's row height to the following:

  1. Select the UITableView from the Document Outline in your storyboard.
  2. Navigate to the Size Inspector in the Utilities area.
  3. Find the Row Height field and change it's value from 44 to 60.

Set Table View Row Height

Making the height of each cell taller gives us a little more room to layout our UI for each note table view cell.

Setting Our Cell UI

With our heighten cells, let's layout our UITableViewCell UI.

Create a vertical stack view with two UILabel on your prototype cell:

Step-by-step:

  1. Drag two labels from the Object Library onto your blank prototype cell. Make sure to position both labels so that one is above the other.
  2. Select both labels simultaneously. You can do this by selecting one label and shift-clicking on the other label.
  3. Click the Embed In Stack button. If the labels are positioned correct, Interface Builder should create a vertical stack view with the selected label.

Next, we'll set our auto-layout constraints for our stack view.

Set constraints for each edge of the stack view:

Step-by-step:

  1. Select the stack view using the Document Outline.
  2. Click the Add New Constraints button and add the following constraints:
    • (Stack View) Top Edge 0pts from Super View (Content View) Top Edge
    • (Stack View) Leading Edge 15pts from Super View Leading Edge
    • (Stack View) Trailing Edge 15pts from Super View Trailing Edge
    • (Stack View) Bottom Edge 0pts from Super View Bottom Edge

Finally, we'll need to add an equal height constraint to our labels to remove some constraint ambiguity.

Set an equal height constraint for both labels within the stack view:

Step-by-step:

  1. Expand your stack view in your Document Outline.
  2. Select both labels within the stack view.
  3. With both labels selected, click the Add New Constraints button.
  4. In the resulting popup, tick the Equal Heights checkbox and click the Add Constraints button.

Nice! Our cell's UI is coming along. So far you should have the following:

Cell With Auto Layout

Adding Some Pizzazz

With our cell's layout setup correctly, it's time to add some styling to our labels.

Let's start with the top label.

In Main.storyboard, set the following attributes for the top (note title) label:

Note Title Attributes

Attributes:

  • Text: Change from Label to Note Title
  • Font: Change from System 17.0 to System 18.0
  • Font Color: Change from Black to the hex color #53A8D2

Next, we'll change the attributes for the last modified timestamp label.

In Main.storyboard, set the following attributes for the bottom (last modified timestamp) label:

Last Modified Timestamp Attributes

Attributes:

  • Text: Change from Label to Last Modified Timestamp
  • Font: Change from System 17.0 to System 15.0
  • Font Color: Change from Black to the hex color #67656C

Next, we'll take a look at connecting our storyboard cell to it's corresponding Swift file.

Setting The Cell Custom Class

Already included in your project, in the Views group, is our custom table view cell subclass named ListNotesTableViewCell.

Open ListNotesTableViewCell.swift from your Project Navigator.

Starting Cell Code

Right now, aside from the class definition, your source file should be empty.

Similar to creating a custom subclass our table view controller, to implement a UITableViewCell subclass, we'll first need to set it's corresponding storyboard object's custom class.

In Main.storyboard, set your storyboard prototype cell's custom class:

Set Cell Custom Class

Step-by-step:

  1. Select your storyboard table view cell using the Document Outline.
  2. Navigate to the Identity Inspector in the Utilities area.
  3. In the Custom Class section, set the Class attribute to ListNotesTableViewCell. Auto-complete should help you select the correct class.

Next, we'll need to create a way to access the title and last modified labels on our ListNotesTableViewCell class. Without a way to access both labels, we won't be able to set or modified them with code.

Sound familiar? IBOutlet to the rescue!

Creating Cell IBOutlets

We'll need to create a corresponding IBOutlet for each of our custom cell's labels. This will allow us to set and access each label programmatically.

Let's start by creating an IBOutlet for our note title label.

First start by opening the Assistant Editor:

  1. Open Main.storyboard from your Project Navigator.
  2. Click on the Show the Assistant Editor button in the tool bar. Open Assistant Editor
  3. (Optionally) Hide both the Navigator and Utilities panes to create more screen space for the Assistant Editor. Hide Navigator and Utilities Panes
  4. (Troubleshooting) If you don't see the ListNotesTableViewCell.swift file show up in the second editor window, change the Assistant Editor file by selecting Manual > MakeSchoolNotes > MakeSchoolNotes > Views > ListNotesTableViewCell.swift in the dropdown above. Troubleshooting Assistant Editor

With our Assistant Editor displaying storyboard file and ListNotesTableViewCell.swift source code side-by-side, we can create each label's IBOutlet.

Create a IBOutlet for each corresponding label:

For each label:

  1. Select the label within the stack view using the Document Outline.
  2. Control-click from the label to the ListNotesTableViewCell class definition in the Assistant Editor.
  3. Name the IBOutlet accordingly:
    • Title Label: noteTitleLabel
    • Last Modified Timestamp: noteModificationTimeLabel

When you're done, you can exit the Assistant Editor and switch back to the Standard editor.

With our new IBOutlet connections, we're now able to access each label property in our ListNotesTableViewCell!

Type Casting Our Cell

Before we move on, we need to make one additional change to table view data source code.

Open ListNotesTableViewController.swift. Take another look at our current implementation of tableView(_:cellForRowAt:).

You should see the following code:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "listNotesTableViewCell", for: indexPath)
    cell.textLabel?.text = "Cell Row: \(indexPath.row) Section: \(indexPath.section)"

    return cell
}

In the code above, our code uses dequeueReusableCell(withIdentifier:for:) to retrieve the appropriate table view cell. The string identifier we've provided as a parameter, matches the Identifier in our storyboard's Identifier attribute.

Matching Cell Identifier

However, our code doesn't know that our storyboard cell has a custom class of ListNotesTableViewCell.

Cell Custom Class

Right now our code thinks cell has the default UITableViewCell type.

Option-click on the cell constraint. You should see the following:

Starting Cell Type

Since Swift is statically-typed, we can option-click on constants/variables and the compiler will show a popup with the current type of cell.

To change this, we'll need to use type casting to tell our code that the cell from the identifier has a custom class of ListNotesTableViewCell.

In ListNotesTableViewController.swift, downcast the cell in tableView(_:cellForRowAt:) to the correct custom class.

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "listNotesTableViewCell", for: indexPath) as! ListNotesTableViewCell

    return cell
}

In the code above, we type cast our cell constant by using the as keyboard with the force unwrap optional !, followed the custom class we want type cast to, in this case, ListNotesTableViewCell. This is referred to as downcasting.

Be careful when downcasting! If the storyboard cell doesn't have it's custom class set to the type you're force casting to, this code will crash your app!

After type casting our cell, you can option-click on our cell constant to see that the type has changed from UITableViewCell to ListNotesTableViewCell.

Type Cast Cell Type

Now that our cell has the correct type, we can also access the ListNotesTableViewCell properties. Let's set both labels that we created an IBOutlet for.

In ListNotesTableViewController.swift, update the method tableView(_:cellForRowAt:) to set each of the labels:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "listNotesTableViewCell", for: indexPath) as! ListNotesTableViewCell
    cell.noteTitleLabel.text = "note's title"
    cell.noteModificationTimeLabel.text = "note's modification time"

    return cell
}

Important: Verify that the code above was updated in your ListNotesTableViewController.swift and not accidentally added to your custom table view cell instead.

Running The App

We've created and implemented a custom table view cell with a new UI! Let's check our progress to make sure everything works as expected. Build and run your app.

At this point, your app should look like the following:

Custom Cell Checkpoint

If everything looks right, you're ready for the next section!

Feedback

If you have feedback on this tutorial or find any mistakes, please open issues on the GitHub Repository or comment below.

Summer academy

An iOS Development Summer Course

Design, code and launch your own app. Locations in San Francisco and Asia

Find your location

Product College

A computer science college

Graduate into a successful career as a founder or software engineer.

Learn more

Cookies on Make School's website

We have placed cookies on your device to ensure that we give you the best experience on our website.

This site uses cookies to deliver our services. By using our site, you acknowledge that you have read and understand our Cookie Policy, Privacy Policy, and our Terms of Service. Your use of Make School’s Products and Services is subject to these policies and terms.

Please note that Make School no longer supports Internet Explorer

We recommend upgrading to a modern web browser. Learn more