Sample CodeiOS, iPadOS, Mac CatalystReviewed 2026-07-21View on Apple Developer

UIKit Catalog: Creating and customizing views and controls

At a glance

Item Summary
Purpose Organize many UIKit control demonstrations behind a data-driven outline and reusable table-case configuration model.
App architecture OutlineViewController turns an OutlineItem hierarchy into a diffable sidebar and routes leaf storyboard names to feature controllers; most feature tables inherit BaseTableViewController and describe control setup with CaseElement closures.
Main patterns Data-driven feature router, Template base controller, Typed configuration closure
Project style Thirty-five Swift files; one catalog/router, a shared table template, and many focused UIKit feature controllers and storyboards.

Project structure

Source bundle/
└── UIKitCatalog/
    ├── AlertControllerViewController.swift
    ├── AppDelegate.swift
    ├── MenuButtonViewController.swift
    ├── OutlineViewController.swift
    ├── PickerViewController.swift
    ├── PointerInteractionButtonViewController.swift
    ├── TextFieldViewController.swift
    ├── ActivityIndicatorViewController.swift
    ├── ButtonViewController.swift
    ├── ProgressViewController.swift
    ├── SegmentedControlViewController.swift
    └── SliderViewController.swift

Structure observations

  • The outline hierarchy is the navigation registry; app/scene delegates only establish lifecycle and initial UI.
  • Feature controllers remain independent examples instead of a single monolithic switch over every control.
  • CaseElement preserves each target view type at construction, then erases it to a uniform UIView configuration closure for the base table.

Overall architecture

Reference code

UIKitCatalog/OutlineViewController.swift:303 — leaf-to-feature routing

    private func pushOrPresentStoryboard(storyboardName: String) {
        let exampleStoryboard = UIStoryboard(name: storyboardName, bundle: nil)
        if let exampleViewController = exampleStoryboard.instantiateInitialViewController() {
            pushOrPresentViewController(viewController: exampleViewController)
        }
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        guard let menuItem = dataSource.itemIdentifier(for: indexPath) else { return }
        if let storyboardName = menuItem.storyboardName {
            pushOrPresentStoryboard(storyboardName: storyboardName)
        }
    }

Interpretation

Navigation and control configuration are both data-driven, at different scales. The outline routes to a feature, while each table feature supplies small typed configuration cases to shared table plumbing. This keeps catalog mechanics reusable without abstracting the individual UIKit APIs away.

Ownership and state

Ownership evidence

UIKitCatalog/OutlineViewController.swift:185 — private navigation registry

    private lazy var menuItems: [OutlineItem] = {
        return [
            controlsOutlineItem,
            viewsOutlineItem,
            pickersOutlineItem
        ]
    }()

    private func configureCollectionView() {
        let collectionView = UICollectionView(
            frame: view.bounds, collectionViewLayout: generateLayout())
        self.outlineCollectionView = collectionView
    }
Owner Object or state Relationship Mutation authority
OutlineViewController Menu hierarchy, collection view, diffable data source Builds and retains all three It creates snapshots and chooses push-versus-detail routing.
Each OutlineItem Title, image name, optional storyboard, child items Value owns its child array It supplies stable identity and route metadata.
BaseTableViewController testCells Subclasses populate the array inherited by the table template The base class owns data-source rendering; feature subclasses own case selection.
CaseElement Title, reuse ID, erased configuration closure Stores the escaping closure value The closure configures only the typed target view captured at initialization.

Composition denotes source-visible construction and retained value state. Aggregation denotes a stored or injected collaborator whose exclusive lifetime the source does not prove.

Class and protocol design

UIKitCatalog/CaseElement.swift:10 — generic-to-erased case configuration

struct CaseElement {
    typealias ConfigurationClosure = (UIView) -> Void
    var configHandler: ConfigurationClosure

    init<V: UIView>(title: String, cellID: String,
                    configHandler: @escaping (V) -> Void) {
        self.title = title
        self.cellID = cellID
        self.configHandler = { view in
            guard let view = view as? V else { fatalError("Impossible") }
            configHandler(view)
        }
    }
}
Type Responsibility Depends on or conforms to
OutlineViewController.OutlineItem Navigation node and stable diffable identifier Hashable through explicit UUID identity
OutlineViewController Builds outline snapshots and routes leaf selection UIViewController, UICollectionViewDelegate
BaseTableViewController Renders one CaseElement per table section UITableViewController template superclass
CaseElement Carries feature-specific view configuration through a uniform base API Generic initializer plus erased (UIView) -> Void closure
Feature view controllers Demonstrate one UIKit control family Usually inherit BaseTableViewController; some use specialized controllers

The catalog relies on UIKit data-source/delegate callbacks and inheritance. It defines no local protocol abstraction; variability is represented by route values, subclasses, and configuration closures.

Access control

Symbol Access Verified effect Design reason
OutlineViewController.menuItems private Only the outline implementation can read or replace the route registry Prevents unrelated features from mutating navigation identity behind the diffable source.
Outline construction/routing helpers private Callable only in the controller’s lexical scope Snapshot and presentation policy stay behind selection callbacks.
BaseTableViewController.testCells implicit internal Feature subclasses in other files can populate it It is intentionally a subclass customization point inside the app module.
CaseElement and feature controllers implicit internal Available across the application target No external package needs the catalog’s teaching types.

Reference code

UIKitCatalog/OutlineViewController.swift:199 — private outline implementation helpers

    private func configureCollectionView() {
        let collectionView = UICollectionView(
            frame: view.bounds, collectionViewLayout: generateLayout())
        view.addSubview(collectionView)
        self.outlineCollectionView = collectionView
        collectionView.delegate = self
    }

    private func configureDataSource() {
        // Cell registrations and the diffable provider stay local.
    }

The shared base class leaves testCells internal because cross-file subclasses must set it. The outline’s registry and mechanics are private because they have no such collaborator. No public, open, or fileprivate API is present.

Logic ownership and placement

Logic Owning type or file Why it lives there
Catalog hierarchy, snapshot, and route selection OutlineViewController It owns both route metadata and adaptive split/navigation presentation.
Generic table-section rendering BaseTableViewController All table-based examples share the same cell/header algorithm.
Control-specific configuration Feature controllers via CaseElement closures The feature knows the exact UIKit type and desired API variants.
Typed closure adaptation CaseElement The generic initializer validates the target once and exposes a uniform stored shape.

Design patterns

Pattern Source evidence Purpose or tradeoff
Data-driven feature router UIKitCatalog/OutlineViewController.swift:245 Uses hierarchical stable values for both navigation UI and destination metadata.
Template base controller UIKitCatalog/BaseTableViewController.swift:10 Shares table plumbing while feature subclasses provide case data.
Typed configuration closure UIKitCatalog/CaseElement.swift:17 Retains type-safe authoring but erases closures for heterogeneous storage.

Naming conventions

  • Feature types name the demonstrated UIKit API (ButtonViewController, SliderViewController, VisualEffectViewController).
  • Shared types name their catalog role (OutlineItem, CaseElement, BaseTableViewController).
  • Routing metadata uses storyboardName; commands use concrete navigation verbs (pushOrPresentStoryboard).
  • Most files follow one primary feature-controller type, with button configurations split into a focused extension file.

Architecture takeaways

  • Represent a large sample catalog as route data, not an app-delegate dependency graph.
  • Use a base controller only for truly repeated table mechanics; leave API-specific setup in feature controllers.
  • A generic initializer plus erased closure can store heterogeneous UIKit configurations without a protocol hierarchy.

Source map

Source file Architectural role
UIKitCatalog/OutlineViewController.swift Navigation hierarchy, diffable sidebar, and feature routing
UIKitCatalog/BaseTableViewController.swift Shared table rendering template
UIKitCatalog/CaseElement.swift Typed control-configuration case abstraction
UIKitCatalog/ButtonViewController.swift / UIKitCatalog/ButtonViewController+Configs.swift Representative feature and configuration split
UIKitCatalog/AlertControllerViewController.swift Representative specialized UIKit example
UIKitCatalog/AppDelegate.swift / UIKitCatalog/SceneDelegate.swift Application and scene lifecycle only