Creating and Using iOS Prototype Cells with Swift


  • Share on Pinterest

Prototype cells in iOS tables do have a learning curve for those not familiar with how they work. I'm going to show you how to create and use them without the pain. Learn once, use many!

Before we start there are a few assumptions made although you can easily follow along regardless of experience.

With that out the way, what are we going to do and why?

Prototype cells are a way to layout the look and feel of a cell inside a table view, they allow us to get a representation of how things are going to work when the application runs and data is passed into the table. These Prototype cells allow for complex layout beyond the basic table view.

In this example I am going to display two labels powered by data from our table data source. This will get you thinking about how you can use them, remember you can place all sorts of things inside a table cell not just text!

The outline of the steps we are going to perform are as follows

  1. Add a table view to our view controller.
  2. Add a prototype cell to our table and add the content we need, in this example it is two label objects.
  3. Create a class for our cell to use, this gives us many abilities going forward but for now it simply gives us a way to create @IBOutlets for our labels to receive data.
  4. Make our view a delegate for the table view, I chose not to use a tableViewController since many times people will want more than just a table on the view.
  5. Create a struct to control the data we will use.
  6. Create a data object and populate it using our struct as the template.
  7. Finally we will tell our table all about the data by telling it how many cells to create and what should go in them based on our prototype cell class we created.

Sounds like a lot? It really is not going to take long, I just want to make sure that all the steps are explained for those starting from scratch. Remember you can always come back to this post anytime you need something, and please share with friends!

Creating the basic layout

First create a new single view application making sure to use the Swift language. Then add a Table View to the View Controller. Now add a Table View Cell to the table, dragging from the objects library to the table on a storyboard is probably the quickest way. You should have something like this

Storyboard with Table and empty prototype cell

At this point we need to give our prototype cell a reuse identifier so it can be referenced in code later on. With the new prototype cell selected go to the utilities panel and select the attributes inspector, in there at the top is a section called ‘Table View Cell' and an entry field labelled as ‘Identifier' enter a name, I went with ‘myProtoCell'

attribute inspector showing prototype cell reuse identifier name

Now we get to start designing our prototype cell. Drag a label to the cell and place it in the top left corner. There is probably no room left so we need to expand the height of the cell by hovering the mouse over the bottom edge of the cell where it should change and let us click and drag to a height big enough for two labels. Do this and then drag a second label below the first.

Prototype cell with two labels.

That is the layout taken care of, now to the code!

Create a new class for our prototype cell

Now we need to create a new class that our prototype cell is going to use, this gives us a convenient way to hook up our labels to @IBOutlets so we can send data into each cell as it is being created.

Create a new file of type Cocoa Touch Class that subclasses UITableViewCell ensuring again that it uses the Swift language. Xcode - New class file creation window

Now we need to go back to our storyboard to assign this new class and make some additions to it.

Back in the storyboard file select the Table View Cell, personally I find the best way is to click on it in the document outline view.

Document outline view with table view cell selected.

With the table view cell selected go to the utilities panel and change to the identity inspector tab if not already selected, note that there is a dropdown labelled ‘Class', in there either by using the dropdown or by typing select the new class you just created.

Utilities tab with new class name selected

Hook up our cell text labels using IBOutlets

Open the Assistant Editor with the table cell selected and you should see the new class appear with the starting code. If the editor does not automatically show the class file then you can use the navigation bar above the editor to select the file so we can start editing.

Either right click or control and click from each of the text labels in the cell to the editor window to create two @IBOutlets.

Storyboard with labels and outlets

Data source creation

For this simple example I am going to use a struct and create our array of data in the controller, clearly this is not something I would expect in the real World but it gets us what we need to make this all work and for me to get the idea across.

Open the ViewController.swift and you should see the standard code that gets created for us.

We are going to use a simple struct as the template for our data source. Just inside the opening class tag add

struct MyData {
    var firstRowLabel:String
    var secondRowLabel:String
}

This gives us two string variables that will store our data. In order to use this new struct and to power the table we will need an array. Below the struct we just created, create a new variable which will be an array that holds a type of our struct.

var tableData: [MyData] = []

The code for your view controller should now look something like this

//
//  ViewController.swift
//  PrototypeCellBasics
//
//  Created by Peter Witham on 7/19/15.
//  Copyright © 2015 Peter Witham. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
    
    struct MyData {
        var firstRowLabel:String
        var secondRowLabel:String
    }
    
    var tableData: [MyData] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

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

The last part is to actually add some data to our array, inside the viewDidLoad() function let's add some rows of data, remember that our struct is going to make it simple! So here is the entire code for the viewDidLoad() function, be sure to use any names that might be different from the ones I have used. I added three items of data to the array.

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    tableData = [
        MyData(firstRowLabel: "The first row", secondRowLabel: "Hello"),
        MyData(firstRowLabel: "The second row", secondRowLabel: "There"),
        MyData(firstRowLabel: "Third and final row", secondRowLabel: "https://peterwitham.com")
    ]
}

Table delegation and data source

With our data created we now need to be responsible for our table and that means delegation!

We need to change our ViewController.swift to act as the delegate and data source for our table, this is done in the usual way by changing

class ViewController: UIViewController {

to

class ViewController:UIViewController, UITableViewDelegate, UITableViewDataSource {

At this point Xcode will start complaining that we have not satisfied the requirements to be a table delegate and we should now make it happy by adding the required functions to do that. First we will add them and then we will customize them to suit what we need, so go ahead if you want and just paste the code below into the view controller. Note that Xcode is still going to complain since we have not completed the code in these functions.

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

}
    
 func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        
}

Completing the code

Now we are ready for the final steps, we have our view taken care of along with a data source, all we need to do is plug them into each other by editing the tableView functions.

We will start with returning the number of items in our data array to give the total number of cells we need to create in the table.

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

The last one is a little more complicated, we create a cell and populate it with data from our data source and then finally return that to be added to the display. This function is called for each cell in the display automatically. I have added code comments to explain what is happening.

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    // Create a new cell with the reuse identifier of our prototype cell
    // as our custom table cell class
    let cell = tableView.dequeueReusableCellWithIdentifier("myProtoCell") as! MyTableCell
    // Set the first row text label to the firstRowLabel data in our current array item
    cell.lblFirstRow.text = tableData[indexPath.row].firstRowLabel
    // Set the second row text label to the secondRowLabel data in our current array item
    cell.lblSecondRow.text = tableData[indexPath.row].secondRowLabel
    // Return our new cell for display
    return cell
}

Anyone that has used tables before and delegation will notice there is one more step, we need to tell our table that our view controller is going to act as the delegate and data source (now that we have completed the code).

To do that you need to either right click or control click on the table and drag up to the View Controller icon at the top of our view controller on the storyboard. When you do this you will get two options, we actually need to do it twice and select both.

Table view dragging to view controller

Table view setting View Controller as delegate and dataSource

Run it!

With everything done go ahead and run the application, I am using the iPhone 5 simulator so I can get the screenshot.

Simulator - iPhone 5 - Truncated labels

Wait a minute! You forgot something!

I did not forget, I wanted to see if anyone would notice! To make everything size correctly we need to use some constraints. The clue was in my assumption list at the beginning of the post!

To make the labels stretch correctly and see our content on any rotation of any size device we need to assign constraints. Thankfully the ones for this application are really simple.

Ensuring that you have the view controller selected go down to the bottom right of the storyboard window and look for the icon on the far right. Click it and a menu should appear with the option ‘Add Missing Constraints' in the all views section, simply click that and Xcode is smart enough to fix the problems for you (but it does not always work so be aware of that in the future!).

Add missing constraints menu

Run the application again and now everything should work just fine at any size and any rotation.

Simulator - iPhone 5 - 3 rows vertical table

Simulator - iPhone 5 - iPhone 5 horizontal table cells

Well done!

Congratulations on making it to the end, yes we covered a lot and you should always come back to this article if you hit a problem or forget something in the future (Pro Tip, I use my own blog posts as reference materials) and please always share with friends on the Internet!

We covered many things but all of them are pretty much standard in iOS development so consider this almost a mini course on getting started.


These tutorials are time consuming to create but I enjoy sharing and giving them to you, if you want to say thanks for the free material then why not share it with friends by clicking any of the share buttons below, I also greatly appreciate any Facebook likes for the page (there might even be more content for you there so go take a look!) and I love interaction on Twitter.


  • @ronm333
    Author
    @ronm333 @ronm333

    Peter,

    How about putting the two labels in a vertical stack view? Then you just do add missing constrains for the stack view.

    Ron

    • Peter Witham
      Author
      Peter Witham Peter Witham

      Hi Ron,

      Yup you could use the new stack view, it took some getting used too but when combined with table cells I’ve found it to be rather useful and certainly makes constraints easier. Thanks for the suggestion!

  • Reuben
    Author
    Reuben Reuben

    Great article – very clear works perfectly!

    Thanks

    • Peter Witham
      Author
      Peter Witham Peter Witham

      Thanks, glad to hear it worked for you.

  • Steven Davis
    Author
    Steven Davis Steven Davis

    That is an amazingly straight to the point and functional demo. I have tried 3 others on this topic that are 4 times longer and don’t work as well.

    Many Thanks.

    • Peter Witham
      Author
      Peter Witham Peter Witham

      Thanks, Steven.

      I am glad to read this, part of my goal with all of my posts is to cut through the usual level of junk and bloat, get straight to the point and give the reader what they need. Which in my opinion is the answer to their problem and some knowledge for them to take it further and start solving the next problem.

  • Scott
    Author
    Scott Scott

    Is there a way to set right detail in the prototype cells? so that information can be displayed on both the left and right hand sides of the cell.

    • Peter Witham
      Author
      Peter Witham Peter Witham

      Hi Scott,

      You should be able to use constraints to achieve a left and right aligned layout.

  • Rowan
    Author
    Rowan Rowan

    Thanks so much for this tutorial, by far the best I’ve found for when tableViewController isn’t the solution – clean, concise and easy to follow. Helped a lot!

    • Peter Witham
      Author
      Peter Witham Peter Witham

      Thanks Rowan, I am so glad it helped you and very much appreciate the comments.

  • ISAI
    Author
    ISAI ISAI

    si quisiera agregar una imagen que tipo seria la variable UIImageView o UIImage ???

    • Peter Witham
      Author
      Peter Witham Peter Witham

      I am sorry, but I do not read/write Spanish. But if I understand the question, you are asking if you can pass an image between the views and I believe that is possible if you create an image type and pass as you would a string.

      I welcome my readers to help out here if they can.

  • David
    Author
    David David

    Great tutorial, Peter! I’ve been scouring the web for accessing objects in a prototype cell and haven’t found anything that answers my question. A tutorial on that would be nice.

    • Peter Witham
      Author
      Peter Witham Peter Witham

      Hi David,

      Thanks! That is a great suggestion, I will look into accessing an object in a prototype cell and report back once I have figured it out 🙂

  • Peter Kasson
    Author
    Peter Kasson Peter Kasson

    Great article … but when I try it, I am getting error:

    fatal error: init(coder:) – : file CustomTableViewCellMessage.swift, line 32

  • Peter Witham
    Author
    Peter Witham Peter Witham

    Hi Peter,

    I am not sure what that error is indicating without more information, I would suggest going back over the steps and making sure you left nothing out, also check that you assigned the outlets, actions and class usages correctly.

    Good luck!

  • Evan Von Oehsen
    Author
    Evan Von Oehsen Evan Von Oehsen

    Hello! I am working in Swift 2 and everything here works great! I just have one big question. I am currently creating an app where I need the text labels in the prototype cell to be side by side, rather than one above the other. When I add the line “cell.lblFirstRow.text = tableData[indexPath.row].firstRowLabel” inside the tableview cellForRowAtIndexPath in the view controller.swift file, it creates an error because the value type of my prototype cell has no member ‘lblFirstRow’. Is there a way to identify the two labels on the cell if they’re side by side? Likewise is there a way to use three or four cells? I hope that my question makes sense.. Thank you in advance

    • Peter Witham
      Author
      Peter Witham Peter Witham

      Hi Evan,

      You should be able to target by creating outlets for both the labels you need. You can change the layout using constraints to get what you need. Or you may want to use a UIStackView to place the two labels side by side and keep things simple.

      Make sense?
      Peter.

  • Stephen
    Author
    Stephen Stephen

    HI. First I am Newbie and I like to cut corners…. Your approach seems to suite me 🙂
    I have tried your code here but it fails me. Question 1. Is it valid code for ios xcode 8.1 and swift 3.
    Question 2. is the graphic correct under ” Back in the storyboard file select the Table View Cell, personally I find the best way is to click on it in the document outline view.” because at this stage you have changed the Reference to ‘myProtoCell’.

    • Peter Witham
      Author
      Peter Witham Peter Witham

      Hi Stephen,

      The code was originally written for Swift 2, without changing to the newer syntax for Swift 3 I do not think it will work ‘as is’. Regarding the other question, you could use the document outline view for sure, I often never think to select things via that view.

      Regards,
      Peter.

      • Stephen
        Author
        Stephen Stephen

        Thanks for quick respond. Have you updated version of code. ?

        • Peter Witham
          Author
          Peter Witham Peter Witham

          I have not updated my old code(s), but I was considering revisiting the older 2.x posts and seeing what needed updating. This might well be one of them now 🙂