Unit 4: TableViews
I. Orientation — The Table-Based Interface
A table view is a UIKit control for displaying vertically scrollable data as rows, optionally divided into sections. UITableView follows a data-source and delegate architecture: the data source supplies content, while the delegate manages appearance, selection, and interaction.
- Defining properties:
- Row-based presentation: Each item is represented by a
UITableViewCell. - Section organization: Rows may be divided into numbered or named sections.
- Cell reuse: Off-screen cells are recycled through reuse identifiers, reducing memory use.
- Data source: An object conforming to
UITableViewDataSourcereports sections, rows, and cells. - Delegate: An object conforming to
UITableViewDelegateresponds to selection and controls presentation details. - Index paths:
IndexPathidentifies a row through itssectionandrowproperties. - Controller integration: A table can be managed by
UITableViewControlleror embedded in an ordinaryUIViewController. - Common styles:
.plainpresents continuous sections..groupedvisually separates sections into groups..insetGroupedpresents inset groups on supported iOS versions.- Main-thread rule: Interface changes, including
reloadData(), must occur on the main thread.
- Row-based presentation: Each item is represented by a
II. UITableView Architecture — Core Roles and Lifecycle
A. UITableView basics
UITableView displays data by repeatedly asking its data source how many rows exist and how each visible cell should be configured.
- Essential objects:
- Table view:
UITableViewowns scrolling, layout, selection, and cell reuse. - Cell:
UITableViewCellrenders one row and may contain text, images, accessories, or custom controls. - Data model: An array or another collection stores the actual application data; the table view is only its visual representation.
- Table view:
- Required data-source methods:
- Row count:
tableView(_:numberOfRowsInSection:)returns the number of model items in a section. - Cell creation:
tableView(_:cellForRowAt:)dequeues and configures a cell for anIndexPath.
- Row count:
- Optional section method:
numberOfSections(in:)defaults to one when it is not implemented. - Reuse process:
- Register a cell class or prototype with a reuse identifier such as
"ItemCell". - Dequeue a reusable cell for the requested index path.
- Replace all reusable content with values from the current model item.
- Register a cell class or prototype with a reuse identifier such as
- Registration example:
tableView.register(
UITableViewCell.self,
forCellReuseIdentifier: "ItemCell"
)- Configuration principle: A reused cell may contain old state, so text, images, accessory types, colors, and control values must all be reset in
cellForRowAt. - Refreshing content:
tableView.reloadData()asks the data source for the complete structure again; targeted insertion, deletion, or reloading is preferable for small animated changes. - Sizing options:
rowHeightassigns a fixed height, whileUITableView.automaticDimensionsupports self-sizing cells whose constraints fully define vertical layout.
III. Basic Construction — Creating and Populating Rows
A. Implementing simple table
A simple table connects an array-backed model to one table section through the required data-source methods.
- Model: The array index corresponds directly to
indexPath.row; for example, row0displays"Phone". - Controller setup:
UITableViewControllersupplies a full-screen table and already exposes it through itstableViewproperty. - Implementation:
final class ItemsViewController: UITableViewController {
private let items = ["Phone", "Tablet", "Watch"]
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(
UITableViewCell.self,
forCellReuseIdentifier: "ItemCell"
)
}
override func tableView(
_ tableView: UITableView,
numberOfRowsInSection section: Int
) -> Int {
items.count
}
override func tableView(
_ tableView: UITableView,
cellForRowAt indexPath: IndexPath
) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(
withIdentifier: "ItemCell",
for: indexPath
)
cell.textLabel?.text = items[indexPath.row]
return cell
}
}- Index-path mapping:
items[indexPath.row]is valid because the reported row count equalsitems.count. - Embedded alternative: In a standard
UIViewController, create an outlet or property for the table, setdataSourceanddelegate, and constrain the table to its container. - Consistency requirement: After changing the model, update the table accordingly; reporting more rows than the array contains causes an out-of-range failure.
- Storyboard prototypes: A prototype cell can carry the identifier
"ItemCell", removing the need for class registration when the storyboard constructs the table.
IV. Cell Presentation — Standard and Custom Content
A. Customizing TableView cells
Cell customization ranges from configuring built-in styles to creating a subclass with a reusable, constraint-based layout.
- Standard content:
- Primary text:
textLabelshows the main value. - Secondary text:
detailTextLabelis available in styles such as.subtitle. - Image:
imageViewdisplays a leading image. - Accessory:
.disclosureIndicator,.checkmark, or.detailButtoncommunicates an available action or state.
- Primary text:
- Standard-style example:
let cell = UITableViewCell(
style: .subtitle,
reuseIdentifier: "ProductCell"
)
cell.textLabel?.text = "iPhone"
cell.detailTextLabel?.text = "In stock"
cell.accessoryType = .disclosureIndicator- Custom subclass: Define views once in
init(style:reuseIdentifier:), add them tocontentView, and activate Auto Layout constraints. Configure only model-dependent values when the cell is reused. - Type-safe dequeueing:
guard let cell = tableView.dequeueReusableCell(
withIdentifier: ProductCell.reuseIdentifier,
for: indexPath
) as? ProductCell else {
fatalError("ProductCell is not registered")
}
cell.configure(with: products[indexPath.row])- Reuse preparation: Override
prepareForReuse()to cancel pending image requests and clear temporary state that configuration may not immediately replace. - Dynamic height: Labels with
numberOfLines = 0and complete top-to-bottom constraints allowautomaticDimensionto calculate row height. - Performance: Avoid expensive synchronous image loading in
cellForRowAt; cache images and update only the cell still representing the intended model item.
V. Sectioned Tables — Organization and Fast Access
A. Grouped and indexed sections
Grouped sections visually classify related rows, while an index provides direct navigation among many alphabetically or logically ordered sections.
-
Grouped sections:
- Data structure: A nested collection represents sections and rows, such as
sections[section].items[row]. - Section count:
numberOfSections(in:)returnssections.count. - Row count:
tableView(_:numberOfRowsInSection:)returnssections[section].items.count. - Style selection: Construct the table with
.groupedor initialize a controller usingUITableViewController(style: .grouped).
- Data structure: A nested collection represents sections and rows, such as
-
Indexed sections:
- Index titles:
sectionIndexTitles(for:)returns short labels such as["A", "B", "C"]. - Mapping:
tableView(_:sectionForSectionIndexTitle:at:)maps the selected index title to a section number. - Ordering condition: The index and section model must use the same stable ordering.
- Index titles:
override func numberOfSections(
in tableView: UITableView
) -> Int {
sections.count
}
override func tableView(
_ tableView: UITableView,
numberOfRowsInSection section: Int
) -> Int {
sections[section].items.count
}
override func sectionIndexTitles(
for tableView: UITableView
) -> [String]? {
sections.map(\.title)
}- Comparison: Grouping communicates relationships through spacing and headings; indexing optimizes movement through a long table. A contact list can use both alphabetical sections and an A–Z index.
VI. Supplementary Content — Context Around Rows
A. Adding header, footer, and image
Headers and footers describe sections or the whole table, while images may appear inside cells or supplementary views.
- Section text:
- Header:
tableView(_:titleForHeaderInSection:)returns a section heading. - Footer:
tableView(_:titleForFooterInSection:)returns explanatory text below a section.
- Header:
- Custom section views:
tableView(_:viewForHeaderInSection:)can return a configuredUITableViewHeaderFooterView; register reusable header/footer classes to avoid repeated allocation. - Whole-table content: Assign a view to
tableHeaderViewortableFooterViewfor content that appears once rather than once per section. - Image in a standard cell:
cell.imageView?.image = UIImage(named: "phone")
cell.textLabel?.text = products[indexPath.row].name- Asset handling:
UIImage(named:)loads a named image from the asset catalog and supports scale variants such as2xand3x. - Remote images: Load asynchronously, cache results, and use a placeholder while waiting. Before assigning a downloaded image, verify that the cell still corresponds to the requested item.
- Layout distinction:
tableHeaderViewscrolls with table content; a separate view constrained above the table remains fixed.
VII. Selection — Responding to User Choice
A. Displaying item selected
Selection is normally handled by the table delegate, which receives the chosen row’s index path.
- Delegate callback:
tableView(_:didSelectRowAt:)runs after the user taps a selectable row. - Model lookup: Use both
indexPath.sectionandindexPath.rowwhen the model contains sections. - Display example:
override func tableView(
_ tableView: UITableView,
didSelectRowAt indexPath: IndexPath
) {
let item = items[indexPath.row]
let alert = UIAlertController(
title: "Selected Item",
message: item,
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true)
tableView.deselectRow(at: indexPath, animated: true)
}- Selection state:
indexPathForSelectedRowreports the current selected row when one exists. - Visual behavior: Deselecting after handling the tap is conventional when selection performs a transient action or opens another screen.
- Persistent choices: For settings, store the selected value in the model and render
.checkmarkaccessories from that model rather than relying only on visible cell state. - Control conflict: Buttons and switches inside a cell may handle their own events, so their actions should identify the relevant model item independently.
VIII. Screen Transitions — Passing the Selected Model
A. Navigating to another view
A selected row can open a detail view by pushing it onto a navigation stack or presenting it modally.
- Navigation controller:
pushViewController(_:animated:)is appropriate for hierarchical movement from a list to item details. - Data transfer: Assign the selected model object to a property on the destination before navigation.
- Programmatic example:
override func tableView(
_ tableView: UITableView,
didSelectRowAt indexPath: IndexPath
) {
let detail = DetailViewController()
detail.item = items[indexPath.row]
navigationController?.pushViewController(
detail,
animated: true
)
}- Storyboard segue: Call
performSegue(withIdentifier:sender:), then useprepare(for:sender:)to configure the destination. - Destination handling: A navigation controller may wrap the real destination, so obtain its top view controller before assigning data when necessary.
- Dependency principle: Pass the selected model value or stable identifier, not the source cell; cells are reusable presentation objects and may leave the screen.
- Disclosure cue: A
.disclosureIndicatoraccessory conventionally signals that tapping the row opens another view. - State restoration: When returning from an editable detail screen, update the source model and reload the affected row so the table reflects the saved changes.
Did this save you a night before the exam?
LPU Notes is free, and it stays free. Ads cover part of the server bill. The rest comes out of a student's own pocket: the domain, the storage, and keeping the site up through the weeks everyone needs it at once.
The payment button didn't load. An ad blocker or a filtered network is the usual reason. to try again.
Nothing here is ever locked, and nothing unlocks. Chip in only if it was worth it. What it pays for →