Latest 1.0.3
License MIT
Platforms ios 9.0

Build Status

Pods Version

UITableView made simple 🙌

Main Features
🙉 Skip the UITableViewDataSource & UITableViewDelegate boilerplate and get right to building your UITableView!
🌀 Closure based API for section and row configuration
📄 Built-in paging functionality
Unit Tested
🐤 Written in Swift 5.0

TableViewLiaison is 🔨 with ❤️ by 📱 @ Shine Labs.


  • Xcode 10.2+
  • iOS 9.0+



The preferred installation method is with CocoaPods. Add the following to your Podfile:

pod 'TableViewLiaison'


To run the example project, clone the repo, and run pod install from the Example directory first.


TableViewLiaison allows you to more easily populate and manipulate UITableView rows and sections.

Getting Started

To get started, all you need to do is liaise an instance of UITableView to with a TableViewLiaison:

let liaison = TableViewLiaison()
let tableView = UITableView()

liaison.liaise(tableView: tableView)

By liaising your tableView with the liaison, the liaison becomes its UITableViewDataSource, UITableViewDelegate, and UITableViewDataSourcePrefetching.
In the event you would like to remove the tableView from the liaison, simply invoke liaison.detach().

TableViewLiaison populates sections and rows using two main types:


struct TableViewSection

To create a section for our tableView, create an instance of TableViewSection and add it to the liaison.

let section = TableViewSection()

let liaison = TableViewLiaison(sections: [section])


let section = TableViewSection()

liaison.append(section: section)

Supplementary Section Views

To notify the liaison that your TableViewSection will display a header and/or footer view, you must provide an instance of TableViewSectionComponentDisplayOption during initialization.

TableViewSectionComponentDisplayOption is an enumeration that notfies the liaison which supplementary views should be displayed for a given section. A header/footer view is represented by:

class TableViewSectionComponent<View: UITableViewHeaderFooterView, Model>

let header = TableViewSectionComponent<UITableViewHeaderFooterView, User>(.dylan)
let section = TableViewSection(componentDisplayOption: .header(component: header))

You can set a static height of a section component by using either a CGFloat value or closure:

header.set(height: .height, 55)

header.set(height: .height) { user -> CGFloat in
    return user.username == "dylan" ? 100 : 75

header.set(height: .estimatedHeight, 125)

In the event a height is not provided for a section component, the liaison will assume the supplementary view is self sizing and return a .height of UITableView.automaticDimension. Make sure you provide an .estimatedHeight to avoid layout complications.

The TableViewSectionComponent views can be customized using func set(command: TableViewSectionComponentCommand, with closure: @escaping (View, Model, Int) -> Void) at all the following lifecycle events:

  • configuration
  • didEndDisplaying
  • willDisplay
header.set(command: .configuration) { view, user, section in
    view.textLabel?.text = user.username

header.set(command: .willDisplay) { view, user, section in
    print("Header: (view) will display for Section: (section) with User: (user)")


class TableViewRow<Cell: UITableViewCell, Model>

To add a row for a section, create an instance of TableViewRow and pass it to the initializer for a TableViewSection or if the row is added after instantiation you can perform that action via the liaison:

let row = TableViewRow<RowTableViewCell, RowModel>(model: RowModel(type: .small))
let section = TableViewSection(rows: [row])
liaison.append(section: section)


let row = TableViewRow<RowTableViewCell, RowModel>(model: RowModel(type: .small))
let section = TableViewSection()
liaison.append(section: section)
liaison.append(row: row)

TableViewRow heights are similarly configured to TableViewSection:

row.set(height: .height, 300)

row.set(height: .estimatedHeight, 210)

row.set(height: .height) { model -> CGFloat in
    switch model.type {
    case .large:
        return 400
    case .medium:
        return 200
    case .small:
        return 50

In the event a height is not provided, the liaison will assume the cell is self sizing and return UITableView.automaticDimension.

The TableViewRow can be customized using func set(command: TableViewRowCommand, with closure: @escaping (Cell, Model, IndexPath) -> Void) at all the following lifecycle events:

  • accessoryButtonTapped
  • configuration
  • delete
  • didDeselect
  • didEndDisplaying
  • didEndEditing
  • didHighlight
  • didSelect
  • didUnhighlight
  • insert
  • move
  • reload
  • willBeginEditing
  • willDeselect
  • willDisplay
  • willSelect
row.set(command: .configuration) { cell, model, indexPath in
    cell.label.text = model.text
    cell.label.font = .systemFont(ofSize: 13)
    cell.contentView.backgroundColor = .blue
    cell.selectionStyle = .none

row.set(command: .didSelect) { cell, model, indexPath in
    print("Cell: (cell) selected at IndexPath: (indexPath)")

TableViewRow can also utilize UITableViewDataSourcePrefetching by using func set(prefetchCommand: TableViewPrefetchCommand, with closure: @escaping (Model, IndexPath) -> Void)

row.set(prefetchCommand: .prefetch) { model, indexPath in

row.set(prefetchCommand: .cancel) { model, indexPath in

Cell/View Registration

TableViewLiaison handles cell & view registration for UITableView view reuse on your behalf utilizing your sections/rows TableViewRegistrationType<T>.

TableViewRegistrationType tells the liaison whether your reusable view should be registered via a Nib or Class.

By default, TableViewRow is instantiated with TableViewRegistrationType<Cell>.defaultClassType.

TableViewSection supplementary view registration is encapsulated by itsTableViewSectionComponentDisplayOption. By default, TableViewSection componentDisplayOption is instantiated with .none.


TableViewLiaison comes equipped to handle your pagination needs. To configure the liaison for pagination, simply set its paginationDelegate to an instance of TableViewLiaisonPaginationDelegate.

TableViewLiaisonPaginationDelegate declares three methods:

func isPaginationEnabled() -> Bool, notifies the liaison if it should show the pagination spinner when the user scrolls past the last cell.

func paginationStarted(indexPath: IndexPath), passes through the indexPath of the last TableViewRow managed by the liaison.

func paginationEnded(indexPath: IndexPath), passes the indexPath of the first new TableViewRow appended by the liaison.

To update the liaisons results during pagination, simply use append(sections: [AnyTableViewSection]) or func append(rows: [AnyTableViewRow]) and the liaison will automatically handle the removal of the pagination spinner.

To use a custom pagination spinner, you can pass an instance AnyTableViewRow during the initialization of your TableViewLiaison. By default it uses PaginationTableViewRow provided by the framework.

Tips & Tricks

Because TableViewSection and TableViewRow utilize generic types and manage view/cell type registration, instantiating multiple different configurations of sections and rows can get verbose. Creating a subclass or utilizing a factory to create your various TableViewRow/TableViewSectionComponent types may be useful.

final class TextTableViewRow: TableViewRow<PostTextTableViewCell, String> {
    init(text: String) {
        registrationType: .defaultNibType)
static func imageRow(with image: UIImage) -> AnyTableViewRow {
    let row = TableViewRow<ImageTableViewCell, UIImage>(image)

    row.set(height: .height, 225)

    row.set(command: .configuration) { cell, image, indexPath in
        cell.contentImageView.image = image
        cell.contentImageView.contentMode = .scaleAspectFill

    return row


TableViewLiaison is a framework in its infancy. It’s implementation is not perfect. Not all UITableView functionality has been liaised just yet. If you would like to help bring TableViewLiaison to a better place, feel free to make a pull request.


✌️ Dylan Shine, [email protected]


TableViewLiaison is available under the MIT license. See the LICENSE file for more info.

Latest podspec

    "name": "TableViewLiaison",
    "version": "1.0.3",
    "summary": "Framework to help you better manage UITableViews.",
    "description": "TableViewLiaison abstracts and simplifies UITableView construction and management.",
    "homepage": "",
    "license": {
        "type": "MIT",
        "file": "LICENSE"
    "authors": {
        "Dylan Shine": "[email protected]"
    "source": {
        "git": "",
        "tag": "1.0.3"
    "platforms": {
        "ios": "9.0"
    "source_files": "TableViewLiaison/Classes/**/*",
    "swift_version": "5.0"

Pin It on Pinterest

Share This