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

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.
This exercise transforms manually created table cells into programmatically generated ones, making the app more maintainable and scalable for adding new content.
Getting Started
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
1Open Previous Project
Launch Jive Factory.xcodeproj from the previous exercise to continue building on existing work
2Remove Static Cells
Delete manually created cells except the first one, which will serve as a template
3Configure Dynamic Prototypes
Change table view content to Dynamic Prototypes and set cell identifier to 'bandCell'
If You Did Not Complete the Previous Exercise (1B)
- Close any open files and return to the Desktop.
- Navigate to Class Files > yourname-iOS Dev Level 2 Class.
- Duplicate the Jive Factory Ready for Table View Controller folder.
- Rename the duplicated folder to Jive Factory.
- 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.
In the Attributes inspector
, 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.
- In the Project navigator, select ViewController.swift. This selection determines the insertion point for our new file in the project structure.
- Navigate to File > New > File to create a new class file.
- Under iOS and Source, double-click the Cocoa Touch Class template, which provides the optimal foundation for iOS view controllers.
- From the Subclass of dropdown, select UITableViewController. Pay careful attention to choose UITableTableViewController rather than UIViewController, as this provides essential table-specific functionality.
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.
- Click Next to proceed to the file location selection.
- Verify you're targeting the Jive Factory folder, then click Create.
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.
- In the Project navigator, select Main to access the storyboard.
- In the Document Outline, select Table View. You may need to expand the Table View Controller Scene hierarchy to locate it.
- In the Utilities panel, click the Connections inspector tab
to examine existing connections. 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.
- Select Table View Controller in the Document Outline to configure its class association.
- Click the Identity inspector tab
in the Utilities panel. 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.
- Press Return to confirm the class assignment.
- Return to the Table View selection in the Document Outline.
- Switch back to the Connections inspector tab
. - Verify that both dataSource and delegate now connect to the Bands Table View Controller. This confirms successful integration between your interface and custom code.
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.
- In the Project navigator, open BandsTableViewController.swift.
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.
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.
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.
- Locate the // MARK: - Table view data source comment, which organizes protocol implementation methods.
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
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 }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.
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 } */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.
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.
- Within the cellForRowAt method, find the // Configure the cell comment.
Replace the comment with code that populates the cell's title label:
// Configure the cell… cell.textLabel?.text = bandTitles[indexPath.row] return cellThis 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.
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.
- Return to Xcode to complete the cell configuration.
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 cellThe parallel array structure ensures that bandTitles[0] and bandSubTitles[0] correspond to the same band's information, maintaining data integrity across multiple properties.
Test the date display by running the application again. Each cell should now show unique show dates.
- Return to Xcode and stop the simulator.
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 cellThe 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.
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.
- Return to Xcode from the Simulator.
- 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.
Around line 128, find and select this delegate method signature:
optional public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat- Copy the method signature with Cmd–C.
- Return to BandsTableViewController.swift using the Project navigator.
Custom Height Implementation
Access UITableView Definition
Control-click UITableView and jump to definition to find height method
Copy Height Method
Locate and copy the heightForRowAt method from UITableView class
Implement Custom Height
Paste method, change to override, and return 88 for consistent cell height
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.