Platformsios 8.0, requires ARC

Build Status
Carthage compatible
CocoaPods Compatible
Swift 4.1

A simple way to create a table view for settings, including:

  • Table view cells with UISwitch
  • Table view cells with center aligned text for tap actions
  • A section that provides mutually exclusive options
  • Actions performed when the row reacts to the user interaction
  • Customizable table view cell image, cell style and accessory type



Set up tableContents in viewDidLoad:

import QuickTableViewController

class ViewController: QuickTableViewController {

  override func viewDidLoad() {

    tableContents = [
      Section(title: "Switch", rows: [
        SwitchRow(title: "Setting 1", switchValue: true, action: { _ in }),
        SwitchRow(title: "Setting 2", switchValue: false, action: { _ in }),

      Section(title: "Tap Action", rows: [
        TapActionRow(title: "Tap action", action: { [weak self] in self?.showAlert($0) })

      Section(title: "Navigation", rows: [
        NavigationRow(title: "CellStyle.default", subtitle: .none, icon: .named("gear")),
        NavigationRow(title: "CellStyle", subtitle: .belowTitle(".subtitle"), icon: .named("globe")),
        NavigationRow(title: "CellStyle", subtitle: .rightAligned(".value1"), icon: .named("time"), action: { [weak self] in self?.showDetail($0) }),
        NavigationRow(title: "CellStyle", subtitle: .leftAligned(".value2"))

      RadioSection(title: "Radio Buttons", options: [
        OptionRow(title: "Option 1", isSelected: true, action: nil),
        OptionRow(title: "Option 2", isSelected: false, action: nil),
        OptionRow(title: "Option 3", isSelected: false, action: nil)
      ], footer: "See RadioSection for more details.")

  // MARK: - Actions

  private func showAlert(_ sender: Row) {
    // ...

  private func showDetail(_ sender: Row) {
    // ...



Subtitle Styles

NavigationRow(title: "UITableViewCellStyle.Default", subtitle: .none)
NavigationRow(title: "UITableViewCellStyle", subtitle: .belowTitle(".subtitle")
NavigationRow(title: "UITableViewCellStyle", subtitle: .rightAligned(".value1")
NavigationRow(title: "UITableViewCellStyle", subtitle: .leftAligned(".value2"))


  • Images in table view cells can be set by specifying the icon of each row.
  • Table view cells in UITableViewCellStyle.value2 will not show the image view.
let icon = Icon.images(normal: UIImage(named: "icon"), highlighted: UIImage(named: "icon-highlighted"))
NavigationRow(title: "Cell with image", subtitle: .none, icon: icon)

Disclosure Indicator

  • A NavigationRow with an action will be displayed in a table view cell with .disclosureIndicator.
  • The action will be invoked when the table view cell is selected.
NavigationRow(title: "Navigation cell", subtitle: .none, action: { (sender: Row) in })


  • A SwitchRow is representing a table view cell with a UISwitch as its accessoryView.
  • The action will be invoked when the switch value changes.
  • The subtitle is disabled in SwitchRow.
SwitchRow(title: "Switch", switchValue: true, action: { (sender: Row) in }),


  • A TapActionRow is representing a button-like table view cell.
  • The action will be invoked when the table view cell is selected.
  • The icon and subtitle are disabled in TapActionRow.
TapActionRow(title: "Tap action", action: { (sender: Row) in })

OptionRow & RadioSection

  • An OptionRow is representing a table view cell with .checkmark.
  • The action will be invoked when the selected state is toggled.
  • The subtitle is disabled in OptionRow.
OptionRow(title: "Option", isSelected: true, action: { (sender: Row) in })
  • OptionRow can be used with or without RadioSection, which allows only one selected option.
  • All options can be unselected in RadioSection by default. Setting alwaysSelectsOneOption to true will keep one of the options selected.



All rows must conform to Row and RowStyle. Additional interface to work with specific types of rows are represented as different protocols:

  • NavigationRowCompatible
  • OptionRowCompatible
  • SwitchRowCompatible
  • TapActionRowCompatible

Cell Classes

A customized table view cell type can be specified to rows during initialization.

// Default is UITableViewCell.
NavigationRow<CustomCell>(title: "Navigation", subtitle: .none)

// Default is SwitchCell.
SwitchRow<CustomSwitchCell>(title: "Switch", switchValue: true, action: { _ in })

// Default is TapActionCell.
TapActionRow<CustomTapActionCell>(title: "Tap", action: { _ in })

// Default is UITableViewCell.
OptionRow<CustomOptionCell>(title: "Option", isSelected: true, action: { _ in })

Since the rows carry different cell types, they can be matched using either the concrete types or the related protocol:

let action: (Row) -> Void = {
  switch $0 {
  case let option as OptionRow<CustomOptionCell>:
    // only matches the option rows with a specific cell type
  case let option as OptionRowCompatible:
    // matches all option rows

Overwrite Default Configuration

You can use register(_:forCellReuseIdentifier:) to specify custom cell types for the table view to use. See CustomizationViewController for the cell reuse identifiers of different rows.

Table view cell classes that conform to Configurable can take the customization during tableView(_:cellForRowAt:):

protocol Configurable {
  func configure(with row: Row & RowStyle)

Additional setups can also be added to each row using the customize closure:

protocol RowStyle {
  var customize: ((UITableViewCell, Row & RowStyle) -> Void)? { get }

The customize closure overwrites the Configurable setup.


As discussed in issue #12, UIAppearance customization works when the cell is dequeued from the storyboard. One way to work around this is to register nib objects to the table view. Check out AppearanceViewController for the setup.


When to use QuickTableViewController?

QuickTableViewController is good for presenting static table contents, where the sections and rows don’t change dynamically after viewDidLoad.

It’s possible to update the table contents by replacing a specific section or row. Using different styles on each row requires additional configuration as described in the Customization section.

When not to use it?

QuickTableViewController is not designed for inserting and deleting rows. It doesn’t handle table view reload animation either. If your table view needs to update dynamically, you might want to consider other solutions such as IGListKit.



~> 1.2
~> 2.0
~> 2.2
~> 2.3
~> 3.0
~> 3.1
~> 3.2
~> 4.0
~> 4.1


Use CocoaPods

Create a Podfile with the following specification and run pod install.

platform :ios, '8.0'

pod 'QuickTableViewController'

Use Carthage

Create a Cartfile with the following specification and run carthage update QuickTableViewController.
Follow the instructions to add the framework to your project.

github "bcylin/QuickTableViewController"

Use Git Submodule

git submodule add -b master [email protected]:bcylin/QuickTableViewController.git Dependencies/QuickTableViewController
  • Drag QuickTableViewController.xcodeproj to your app project as a subproject.
  • On your application target’s Build Phases settings tab, add QuickTableViewController-iOS to Target Dependencies.


QuickTableViewController is released under the MIT license.
See LICENSE for more details.
Image source: iconmonstr.

Latest podspec

    "name": "QuickTableViewController",
    "version": "0.9.1",
    "summary": "A simple way to create a UITableView for settings.",
    "screenshots": [
    "homepage": "",
    "license": {
        "type": "MIT",
        "file": "LICENSE"
    "authors": "bcylin",
    "platforms": {
        "ios": "8.0"
    "source": {
        "git": "",
        "tag": "v0.9.1"
    "source_files": "Source/**/*.swift",
    "requires_arc": true

Pin It on Pinterest

Share This