UITableViewCell Subclass In Swift For Dynamic Cell Reuse

This tutorial demonstrates implementation in Swift of Dynamic Prototype cells for a UITableView using a custom UITableViewCell subclass.

Update 3 Aug 2017: Demo app is updated for Swift 3.

Before we get started, a refresher on what we mean by a dynamic prototype versus static cell.

Static cells are for cases where there is a finite number of rows to display, and you can configure the complete layout of the table at design time, including number of rows, headers, and footers. A common use case is for a settings screen, where you know exactly what you want in each row, how many rows there will be, number of sections and headers you want, and in what order the rows should be. Another common scenario for a static cell is for the detail view of an item that you want displayed as rows and sections of data for that one item.

In contrast, dynamic prototypes are for designing a cell layout but reusing that cell for multiple rows of data that you retrieve at runtime. For example, you might retrieve items from a local database or remote API and want to display them all the same way, but you do not know how many items you will retrieve. In this case, you define a dynamic prototype cell, and for each item that the table will display, an instance of the prototype UITableViewCell (or a subclass) is dequeued for the item. As you scroll and rows disappear from the screen, for performance reasons those now unused cells are reused for a newly displayed row.

It is also possible to mix static cells and dynamic prototypes, and to have multiple prototypes and determine which one to use based on indexPath, but in this tutorial we will not address those two techniques.

Let’s start with a Single View Application template, and I’ll add a UITableView under the View. I’ll add typical constraints with constants = 0 to make the UITableView align top/bottom/leading/trailing edges with the parent View. In the Storyboard we now have the following.

Screen Shot 2016-04-26 at 3.23.17 PM

Since I’ve put the UITableView in a UIViewController versus a UITableViewController,  we need to declare that the controller conforms to the UITableViewDataSource and UITableViewDelegate protocols. I’ll make those declarations and also create an IBOutlet for the table so we have access to it in code. We’ll now have the following for the ViewController class.

You’ll see errors because we have not yet defined the methods required by the two protocols. Let’s define the kind of UITableViewCell we want first. In Table View > Content, it should default to Dynamic Prototypes, which is what we want. Change Prototype Cells from 0 to 1. We’ll just define one dynamic prototype for this project, since all cells will contain the same data.

Under Table View in the Storyboard, you’ll now see a Table View Cell, and a Content View for the new cell prototype. Inside the Content View is where we will define the controls we want. For this project, I’m going to use famous quotes as the data, with the quote and author in each cell. We want the author on the bottom, and the quote on the top.

Drag a UILabel to be under the Content View, and then drag a second UILabel to be under the first one in the outline. Highlight the two labels and select the Stack View icon in the storyboard. You can see that in the next screenshot via the red arrow. Ensure that the UIStackView is set to be Vertical Axis, Alignment FillDistribution Fill, and Spacing = 5.

For the top label, left align it, and set the Lines value to 0. This means it will grow to accommodate multiple lines in the label. For the bottom label, right align it, but leave lines equal to 1, since the author will fit on one line. For clarity, I also changed the label names in the Storyboard to be Quote Label and Author Label.

Create constraints for the stack view so that it is constrained equally to the Content View leading, trailing, top, and bottom, and set constants to 7. This means it will use up all the space in the table view cell, but leave insets on all edges of the cell. Uncheck the Relative to margin for the leading and trailing constraints.

Set the Vertical Compression Resistance and Content Hugging for the Author Label to 251 so that its intrinsic size is prioritized. At runtime, since we’ll resize rows automatically this will have no impact, but Auto Layout needs to know which label to prioritize given that we have two in the same stack view.

In the Size Inspector, set the Table View Cell > Row Height to 70 so that we can see both labels properly. This does not affect runtime size, and in fact we’ll set it to be dynamic so that variable size quotes are handled nicely. Use the yellow arrow to update frames of misplaced views. If xCode shows the yellow arrow even after doing this, close Main.storyboard and reopen it, as this sometimes happens. This is what it should now look like.

stackviewarrow

 

Now we can define the UITableViewCell subclass. Create a new Cocoa Touch Class, name it QuoteTableViewCell, and make it a subclass of UITableViewCell. Do not create a Xib file. We’ll need IBOutlet properties for the labels, but first we have to specify that the Table View Cell in the Storyboard is of type QuoteTableViewCell. In the Identity Inspector, change Custom Class > Class to be QuoteTableViewCell.

Create IBOutlets in the QuoteTableViewCell class for the two UILabels. Name them quoteLabel and authorLabel. This class now is as follows.

We also need to specify a reuse Identifier, so in the Attributes Inspector, for Table View Cell > Identifier, enter “quoteCell“. This is the value that will identify what kind of dynamic cell we want to use for each row in the table. You’ll see this value used in cellForRowAtIndexPath shortly.

Just so the view isn’t too boring, let’s set View > Background of the table to Sky blue. This means we need to set the backgrounds of quoteCell, Content View, and the two labels to Clear Color in order to see the table color.

We can soon add the required protocol methods for the data source and delegate protocols, but first we need a few other additions to the ViewController class. We’ll add a Quote struct, array of quotes, set the delegate and data source, avoid separators where there is no data, and have the table automatically size each row based on contained data. I’ve added comments in the code.

Now we can add the required protocol methods to ViewController. Here are those methods defined, with comments to explain the code.

We can run it now, and it will look as follows with one row selected.

Simulator Screen Shot Apr 27, 2016, 11.02.02 AM

You can see that we have successfully used the dynamic prototype cell, and set values for the two labels in each row using the properties in the corresponding QuoteTableViewCell subclass.

You can download this project from GitHub.

Leave a Comment: