Need help with ObjectForm?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

172 Stars 11 Forks Apache License 2.0 86 Commits 3 Opened issues


A simple yet powerful Swift library to build form for your class models.

Services available


Need anything else?

Contributors list

# 554,081
13 commits
# 74,030
5 commits



A simple yet powerful library to build form for your class models.


I found most form libraries for swift are too complicated to bootstrap a simple project. So I write ObjectForm to make it dead simple for building forms and binding model classes.

ObjectForm doesn't fight with you to write UIKit code. By design, it is simple to understand and extend. If you follow the example project carefully, you would find it easy to fit in your Swift project.

This project has no dependency of any other library.


In my application (a personal finance app), I use ObjectForm to make forms for multiple classes as well as different variants for the same class, which saves me from writing duplicate code.


  • Bind class model to form rows
  • Automatic keyboards types according to model types
  • Form rows are type safe
  • Fully customizable form validation rules
  • A list of built-in UITableViewCell to support multiple types
  • Work amazingly well with your UITableView code


  • iOS >= 11.0


  1. Copy sources
    • Copy files under /Sources into your project.
  2. Carthage (Coming soon)
  3. Swift Package Manager
    • Click "Files -> Swift Package Manager -> Add Package Dependency..." in Xcode's menu
    • Search "".
    • Select "master" branch or input "Next major version"

Available Rows & Cells


  • StringRow
    : Row to support string input, full keyboard
  • DoubleRow
    : Row to support number input, numeric keyboard
  • DateRow
    : Row to bind Date value


  • TextViewInputCell
    : text input cell
  • SelectInputCell
    : support selection, provided by
  • TextViewVC
    : A view controller with UITextView to input long text
  • ButtonCell
    : Show a button in the form
  • TypedInputCell
    : Generic cell to support type binding
  • FormInputCell
    : The base class for all cells


You can follow ObjectFormExample in

to learn how to build a simple form with a class model.

Binding Model to Form

class FruitFormData: NSObject, FormDataSource {
      // Bind your custom model
      typealias BindModel = Fruit
      var basicRows: [BaseRow] = []

  func numberOfSections() -> Int {...}
  func numberOfRows(at section: Int) -> Int {...}
  func row(at indexPath: IndexPath) -> BaseRow {...}

  self.bindModel = fruit

  basicRows.append(StringRow(title: "Name",
                             icon: "",
                             kvcKey: "name",
                             value: ?? "",
                             placeholder: nil,
                             validator: nil))

  // Row are type safe
  basicRows.append(DoubleRow(title: "Price",
                             icon: "",
                             kvcKey: "price",
                             value: fruit.price,
                             placeholder: "",
                             validator: nil))

  // You can build as many rows as you want
  basicRows.append(TextViewRow(title: "Note",
                               kvcKey: "note",
                               value: fruit.note ?? "-"))

} }

Showing FormDataSource in a UITableView

class FruitFormVC: UIViewController {
  private let dataSource: FruitFormData

extension FruitFormVC: UITableViewDataSource { func numberOfSections(in tableView: UITableView) -> Int { return dataSource.numberOfSections() }

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    dataSource.numberOfRows(at: section)

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let row = dataSource.row(at: indexPath)
    row.baseCell.delegate = self
    return row.baseCell


Listening to Cell Value Change

extension FruitFormVC: FormCellDelegate {
    func cellDidChangeValue(_ cell: UITableViewCell, value: Any?) {
        let indexPath = tableView.indexPath(for: cell)!
        _ = dataSource.updateItem(at: indexPath, value: value)

Data Validation

By providing a validation block when building a row, you can provide any validaiton rules.

basicRows.append(StringRow(title: "Name",
                           icon: "",
                           kvcKey: "name",
                           value: ?? "",
                           placeholder: nil,
                           validator: {
                           // Custom rules for row validation
                            return !( ?? true)


@objc private func saveButtonTapped() {
    guard dataSource.validateData() else {

navigationController?.popViewController(animated: true)


Row Type Safety

Since a form row use key-value-coding to update its bind model, it is important to keep the row value type the same as the object's variable type. ObjectForm enforces type safe. Every row must implement the following method:

open override func isValueMatchRowType(value: Any) -> Bool

This is already implemented by built-in generic rows, for example,


Make Your Own Row

Making your own row and cell is easy. You have 2 options:

  1. Create concrete type using
typealias StringRow = TypedRow
  1. Subclass
class TextViewRow: BaseRow {

public override var baseCell: FormInputCell {
    return cell

public override var baseValue: CustomStringConvertible? {
    get { return value }
    set { value = newValue as? String }

var value: String?

var cell: TextViewInputCell

open override func isValueMatchRowType(value: Any) -> Bool {
    let t = type(of: value)
    return String.self == t

override var description: String {
    return "<textviewrow> \(title ?? "")"

required init(title: String, kvcKey: String, value: String?) {
    self.cell = TextViewInputCell()


    self.title = title
    self.kvcKey = kvcKey
    self.value = value
    self.placeholder = nil


Do not subclass built-in rows and cells (indeed it is not possible because they are not open classes), because they are subject for change.

Instead, use them as a template to create your own version.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.