Skip to main content
April 1, 2026Noble Desktop Publishing Team/10 min read

Building a Table View Controller

Master Dynamic Table Views in iOS Development

Core iOS Table View Concepts

UITableViewController

A specialized view controller that manages table views with built-in data source and delegate protocols for dynamic content management.

Data Source Protocol

Defines methods that provide data to table views, including section counts, row counts, and cell configuration for dynamic population.

Dynamic Prototypes

Reusable cell templates that can be programmatically populated with different data, replacing static manually-created cells.

Topics Covered in This iOS Development Tutorial:

Connecting a Custom Class to the Storyboard, Adding Properties for Data Management, and Implementing Essential Datasource Protocol Methods

Exercise Preview

ex prev table view

Exercise Overview

The static list of upcoming shows from our previous exercise provides a good foundation, but professional iOS applications require dynamic cell generation for maintainability and scalability. Hardcoded table cells become unwieldy as data grows and changes frequently. In this exercise, we'll implement programmatic table view population, transforming our static interface into a dynamic, data-driven system that can easily accommodate new shows, schedule changes, and varying content types.

This approach follows modern iOS development best practices and prepares your application for real-world scenarios where data typically comes from APIs, databases, or other dynamic sources.

From Static to Dynamic

This exercise transforms manually created table cells into programmatically generated ones, making the app more maintainable and scalable for adding new content.

Getting Started

  1. If you completed the previous exercise successfully, you can skip the following sidebar. We strongly recommend completing exercise 1B before proceeding, as it establishes the essential UI foundation we'll be enhancing.

    If you completed the previous exercise, Jive Factory.xcodeproj should still be open in Xcode. If you closed it, navigate to yourname-iOS Dev Level 2 Class > Jive Factory and reopen the project file.

    Project Setup Process

    1

    Open Previous Project

    Launch Jive Factory.xcodeproj from the previous exercise to continue building on existing work

    2

    Remove Static Cells

    Delete manually created cells except the first one, which will serve as a template

    3

    Configure Dynamic Prototypes

    Change table view content to Dynamic Prototypes and set cell identifier to 'bandCell'

If You Did Not Complete the Previous Exercise (1B)

  1. Close any open files and return to the Desktop.
  2. Navigate to Class Files > yourname-iOS Dev Level 2 Class.
  3. Duplicate the Jive Factory Ready for Table View Controller folder.
  4. Rename the duplicated folder to Jive Factory.
  5. Open Jive Factory > Jive Factory.xcodeproj.
  • We'll preserve the visual design and layout of our existing cells while transitioning to dynamic generation. The first cell will serve as our reusable prototype, eliminating the need for multiple static instances.

    In the Document Outline, select the second Ambulance LTD cell.

  • Hold Shift and click on the final Black Angels cell to select all remaining static cells.
  • Press Delete to remove the redundant cells.
  • In the Document Outline, select Table View to access its configuration options.
  • In the Attributes inspector attributes inspector icon, locate the Content dropdown and select Dynamic Prototypes. This fundamental change enables programmatic cell generation.
  • In the Document Outline, select Table View Cell to configure our prototype.
  • In the Attributes inspector attributes inspector icon, locate the Identifier field, enter bandCell, and press Return. This identifier acts as a unique key that allows our code to reference and instantiate this specific cell design programmatically.

  • Creating a Custom Table View Controller Class

    Professional iOS development requires custom classes to manage complex data interactions and business logic. We'll create a specialized table view controller that extends Apple's UITableViewController with our specific functionality for band data management.

    1. In the Project navigator, select ViewController.swift. This selection determines the insertion point for our new file in the project structure.
    2. Navigate to File > New > File to create a new class file.
    3. Under iOS and Source, double-click the Cocoa Touch Class template, which provides the optimal foundation for iOS view controllers.
    4. From the Subclass of dropdown, select UITableViewController. Pay careful attention to choose UITableTableViewController rather than UIViewController, as this provides essential table-specific functionality.
    5. Set the Class name to: BandsTableViewController

      By subclassing UITableViewController, our custom class inherits all standard table view functionality while allowing us to add specialized behavior for band data management. This inheritance-based approach ensures compatibility with iOS frameworks while providing customization flexibility.

    6. Click Next to proceed to the file location selection.
    7. Verify you're targeting the Jive Factory folder, then click Create.
    8. Notice that BandsTableViewController.swift now appears in the Project navigator. We now have a clean foundation for implementing our data-driven table view logic.

    Connecting the Class to the Storyboard

    Interface Builder connections bridge the gap between your visual interface design and underlying code functionality. This connection enables our custom class to control the table view's behavior and data presentation.

    1. In the Project navigator, select Main to access the storyboard.
    2. In the Document Outline, select Table View. You may need to expand the Table View Controller Scene hierarchy to locate it.
    3. In the Utilities panel, click the Connections inspector tab connections inspector icon to examine existing connections.
    4. Observe the two critical outlets connected to the Table View Controller: dataSource and delegate.

      These outlets represent fundamental iOS design patterns called protocols—formal contracts that define required methods for specific functionality. The dataSource protocol manages data provision and cell configuration, while the delegate protocol handles user interactions and display customization. When you initially drag a table view controller from the Object Library, it automatically assigns itself as both dataSource and delegate. By connecting our custom class, we gain programmatic control over these essential functions.

    5. Select Table View Controller in the Document Outline to configure its class association.
    6. Click the Identity inspector tab identity inspector icon in the Utilities panel.
    7. In the Class field, type B and Xcode should autocomplete to BandsTableViewController.

      Xcode's intelligent code completion system occasionally requires a moment to index new classes. If autocomplete doesn't appear immediately, manually type the complete class name.

    8. Press Return to confirm the class assignment.
    9. Return to the Table View selection in the Document Outline.
    10. Switch back to the Connections inspector tab connections inspector icon.
    11. Verify that both dataSource and delegate now connect to the Bands Table View Controller. This confirms successful integration between your interface and custom code.
    12. Save your work with File > Save or Cmd–S.

    Essential Table View Protocols

    DataSource Protocol

    Provides data to the table view including number of sections, rows per section, and cell content configuration.

    Delegate Protocol

    Handles table view behavior including row selection, editing, and custom appearance settings like row height.

    Adding Properties for Band Data Management

    Effective data architecture forms the backbone of maintainable iOS applications. Before implementing table view rendering logic, we need structured data representations for band information that our interface will display.

    1. In the Project navigator, open BandsTableViewController.swift.
    2. Near the top of the class declaration, add the band titles array:

      class BandsTableViewController: UITableViewController {
      
         let bandTitles = ["Nicole Atkins", "Ambulance LTD", "Sleepies", "Black Angels"]
      
         override func viewDidLoad() {

      This implementation uses Swift's array collection type to maintain an ordered list of band names. The let declaration creates an immutable constant—once initialized, the array contents cannot be modified. This approach provides data integrity and performance benefits. Swift's type inference automatically recognizes this as a [String] array, ensuring type safety throughout your application.

    3. Add the remaining data properties to create a complete band information structure:

      let bandTitles = ["Nicole Atkins", "Ambulance LTD", "Sleepies", "Black Angels"]
      let bandSubTitles = ["Tue 5/1", "Fri 5/4", "Sat 5/5", "Sun 5/6"]
      let bandImageNames = ["thumb-nicole-atkins", "thumb-ambulance-ltd", "thumb-sleepies.png", "thumb-black-angels"]
      
      override func viewDidLoad() {

      This parallel array structure maintains data relationships through consistent indexing. While suitable for this tutorial, production applications typically use more sophisticated data models like custom structs or Core Data entities for complex relational data.

    4. Save your progress with File > Save.

    Implementing Essential Datasource Protocol Methods

    The UITableViewDataSource protocol defines the contract between your data and the table view's rendering system. Xcode's class template provides commented scaffolding for common methods—we'll implement the three essential methods that control table structure and content.

    1. Locate the // MARK: - Table view data source comment, which organizes protocol implementation methods.
    2. Below this section, identify the three critical methods we'll implement:

      • numberOfSections - defines table structure
      • numberOfRowsInSection - specifies row count per section
      • cellForRowAt - configures individual cell appearance and content
    3. Begin with numberOfSections, which tells the table view how many distinct sections to render. For our single-section design, modify the return value:

      override func numberOfSections(in tableView: UITableView) -> Int {
         // #warning Incomplete implementation, return the number of sections
         return 1
      }
    4. The numberOfRowsInSection method calculates rows per section. Since our data drives the display, we'll return the count of our band array:

      override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
         // #warning Incomplete implementation, return the number of rows
         return bandTitles.count
      }

      This approach leverages Swift's count property to dynamically determine row quantity. As your band list grows or shrinks, the table automatically adjusts without code modifications. The table view uses this count to determine how many times to call cellForRowAt.

      The cellForRowAt method handles individual cell configuration. It receives an indexPath parameter indicating the current section and row, enabling precise data-to-cell mapping.

    5. Uncomment the cellForRowAt method by removing the comment delimiters:

      /*
      override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
         let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
      
         // Configure the cell…
      
         return cell
      }
      */
    6. Locate this line within the method:

      let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)

      The table view's cell reuse system optimizes memory and performance by recycling off-screen cells. We must specify our custom identifier to retrieve the correct prototype.

    7. Update the identifier to match our storyboard configuration:

      let cell = tableView.dequeueReusableCell(withIdentifier: "bandCell", for: indexPath)

      The dequeueReusableCell method efficiently manages cell instances, creating new cells only when necessary and reusing existing ones for optimal performance. The indexPath parameter provides precise section and row information for data mapping.

    Customizing Cell Content with Dynamic Data

    With our data structure and basic table configuration complete, we'll implement the cell customization logic that transforms our static prototype into dynamic, data-driven content.

    1. Within the cellForRowAt method, find the // Configure the cell comment.
    2. Replace the comment with code that populates the cell's title label:

      // Configure the cell…
      cell.textLabel?.text = bandTitles[indexPath.row]
      return cell

      This code accesses the cell's built-in textLabel property and assigns text from our bandTitles array. The indexPath.row value corresponds directly to array indices, creating a precise data-to-display mapping. The optional chaining operator (?) safely handles potential nil values.

    3. Test the current implementation by clicking the Run button. The Simulator will display four cells with distinct band titles, though you'll notice the cells appear shorter than our previous static implementation.

    4. Return to Xcode to complete the cell configuration.
    5. Add the subtitle (date) information using the same indexPath-based approach:

      // Configure the cell…
      cell.textLabel?.text = bandTitles[indexPath.row]
      cell.detailTextLabel?.text = bandSubTitles[indexPath.row]
      return cell

      The parallel array structure ensures that bandTitles[0] and bandSubTitles[0] correspond to the same band's information, maintaining data integrity across multiple properties.

    6. Test the date display by running the application again. Each cell should now show unique show dates.

    7. Return to Xcode and stop the simulator.
    8. Image handling requires additional complexity since we store filenames rather than image objects. Add the image configuration code:

      // Configure the cell…
      cell.textLabel?.text = bandTitles[indexPath.row]
      cell.detailTextLabel?.text = bandSubTitles[indexPath.row]
      cell.imageView?.image = UIImage(named: bandImageNames[indexPath.row])
      return cell

      The UIImage(named:) initializer searches the application bundle for image files matching the provided filename. This approach automatically handles different image resolutions (@2x, @3x) and file formats, providing optimal images for various device capabilities.

    9. Run the application to verify complete cell customization. You should see four distinct cells with unique titles, dates, and images, all generated programmatically from your data arrays.

    Specifying Custom Table Cell Height

    Dynamic table views use default cell heights that often differ from custom static designs. Professional applications require precise control over visual presentation, including cell dimensions that accommodate content and maintain design consistency.

    The UITableViewDelegate protocol provides height customization methods that aren't automatically included in the template since they're optional and context-specific.

    1. Return to Xcode from the Simulator.
    2. Around line 44, locate the UITableView class reference. Hold Control and click on it, then select Jump to Definition from the context menu. This navigates to Apple's UITableView class documentation.
    3. Around line 128, find and select this delegate method signature:

      optional public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
    4. Copy the method signature with Cmd–C.
    5. Return to BandsTableViewController.swift using the Project navigator.

    Custom Height Implementation

    1

    Access UITableView Definition

    Control-click UITableView and jump to definition to find height method

    2

    Copy Height Method

    Locate and copy the heightForRowAt method from UITableView class

    3

    Implement Custom Height

    Paste method, change to override, and return 88 for consistent cell height

    Dynamic Table Complete

    The table view now programmatically generates cells with custom data and styling, making it easy to add new bands by simply updating the data arrays.

    Key Takeaways

    1UITableViewController provides built-in data source and delegate protocols for managing dynamic table content
    2Dynamic prototypes replace static cells, enabling programmatic population with reusable cell templates
    3Data source protocol requires three key methods: numberOfSections, numberOfRowsInSection, and cellForRowAt
    4Array-based data storage with indexPath.row creates dynamic association between data and table rows
    5Cell customization involves setting textLabel, detailTextLabel, and imageView properties programmatically
    6UIImage(named:) method loads local images by filename for dynamic cell image assignment
    7Custom cell height requires implementing heightForRowAt delegate method with override keyword
    8Connecting storyboard elements to custom classes enables code-driven table view behavior and appearance

    RELATED ARTICLES