Making table cells reorderable

This tutorial shows how to make UITableView cells reorderable:

Reorderable/Movable table cells

  1. Use your TableExample project from the introductory UITableViewController tutorial or download TableExample.zip as a starting point.

  2. In FruitsTableViewController, overwrite the UIViewController method viewDidLoad and enable the editing mode for the UITableView:

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.isEditing = true
    }

    Alternatively, you can add an Edit button as Right Bar Button Item:

    Edit Button Item

    To enable this, set the rightBarButtonItem to the editButtonItem of the Table View Controller instead of enabling the editing mode immediately:

    self.navigationItem.rightBarButtonItem = self.editButtonItem
  3. Enabling the edit mode causes delete buttons to be visible for all cells:

    Delete Buttons

    Disable the buttons by implementing these UITableViewDataSource methods:

    override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
        return .none
    }
    
    override func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
        return false
    }
  4. Enable the reorder control to move cells by overwriting tableView:moveRowAtIndexPath: and implement the method so that the elements in the underlying data list are updated:

    override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
        let movedObject = self.fruits[sourceIndexPath.row]
        fruits.remove(at: sourceIndexPath.row)
        fruits.insert(movedObject, at: destinationIndexPath.row)
        NSLog("%@", "\(sourceIndexPath.row) => \(destinationIndexPath.row) \(fruits)")
        // To check for correctness enable: self.tableView.reloadData()
    }

    Hint: The table view is not reloaded after the move operation - UITableView trusts you to change the underlying model list accordingly. If you have a bug in your implementation, the UI will show the moved cell as moved by the user, but the data object will have a different order. To check for the correctness of your implementation, use NSLog or reload the table after the move operation.

    Hint: Many examples advise setting cell.showsReorderControl. This is not necessary, the control is automatically shown when you implement tableView:moveRowAtIndexPath:. Optionally you can overwrite canMoveRowAtIndexPath:

    override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
        let rowData = fruits[indexPath.row]
        return rowData.hasPrefix("A")
    }

    to enable the reorder control only for some rows:

    canMoveRowAtIndexPath for every second row

  5. Run the app with ⌘R:

    Table move

Example code

Ralf Ebert Ralf Ebert is an independent software developer and trainer for Mac OS X and iOS. He makes the Page Layers and Straight ahead apps and conducts iOS trainings in Germany since 2009.