UITableViewCell
swipe to delete
iOS development
Swift programming
mobile app UI

Add swipe to delete UITableViewCell

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Swipe-to-delete in UITableView is a standard iOS interaction pattern that users expect in list interfaces. UIKit provides built-in APIs for this behavior, but production code also needs data consistency, undo support, and safe async deletion flows. This guide covers modern implementations for both basic and custom swipe actions.

Basic Swipe-to-Delete With Data Source API

The classic API is tableView(_:commit:forRowAt:). When the user confirms delete, remove the model item first, then update table rows.

swift
1import UIKit
2
3final class TodosViewController: UITableViewController {
4    private var items = ["Buy milk", "Read docs", "Call team"]
5
6    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
7        items.count
8    }
9
10    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
11        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") ?? UITableViewCell(style: .default, reuseIdentifier: "Cell")
12        cell.textLabel?.text = items[indexPath.row]
13        return cell
14    }
15
16    override func tableView(_ tableView: UITableView,
17                            commit editingStyle: UITableViewCell.EditingStyle,
18                            forRowAt indexPath: IndexPath) {
19        guard editingStyle == .delete else { return }
20
21        items.remove(at: indexPath.row)
22        tableView.deleteRows(at: [indexPath], with: .automatic)
23    }
24}

This is enough for simple local data lists.

Custom Swipe Actions With UIContextualAction

For modern UI customization, use trailing swipe actions. This enables delete plus extra actions such as archive or flag.

swift
1import UIKit
2
3final class MessagesViewController: UITableViewController {
4    private var messages = ["Invoice sent", "Build passed", "Deploy complete"]
5
6    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
7        messages.count
8    }
9
10    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
11        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") ?? UITableViewCell(style: .default, reuseIdentifier: "Cell")
12        cell.textLabel?.text = messages[indexPath.row]
13        return cell
14    }
15
16    override func tableView(_ tableView: UITableView,
17                            trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath)
18    -> UISwipeActionsConfiguration? {
19        let delete = UIContextualAction(style: .destructive, title: "Delete") { [weak self] _, _, completion in
20            guard let self = self else { return completion(false) }
21            self.messages.remove(at: indexPath.row)
22            tableView.deleteRows(at: [indexPath], with: .automatic)
23            completion(true)
24        }
25
26        let config = UISwipeActionsConfiguration(actions: [delete])
27        config.performsFirstActionWithFullSwipe = true
28        return config
29    }
30}

This API is preferred for richer interaction design.

Keeping Model and UI in Sync

Deletion bugs usually come from updating UI and model in inconsistent order. Always mutate your source of truth first, then animate row deletion.

For diffable data sources, do not call deleteRows manually. Instead, apply an updated snapshot.

swift
var snapshot = dataSource.snapshot()
snapshot.deleteItems([itemToDelete])
dataSource.apply(snapshot, animatingDifferences: true)

Mixing diffable updates with manual row mutations can crash with invalid update exceptions.

Async Server Deletion Pattern

If deletion requires an API call, decide whether to use optimistic or pessimistic UI update:

  • optimistic: remove immediately, rollback on failure
  • pessimistic: wait for server success, then remove

Optimistic example outline:

swift
1func deleteItem(at indexPath: IndexPath) {
2    let deleted = items.remove(at: indexPath.row)
3    tableView.deleteRows(at: [indexPath], with: .automatic)
4
5    apiDelete(item: deleted) { [weak self] success in
6        guard let self = self, !success else { return }
7        self.items.insert(deleted, at: indexPath.row)
8        self.tableView.insertRows(at: [indexPath], with: .automatic)
9    }
10}

This keeps UI responsive but requires robust rollback handling.

Add Undo for Better UX

Users frequently trigger swipe delete by mistake. An undo option improves trust.

Common patterns:

  • show snackbar style message with undo action
  • support system undo manager for editable content
  • keep deleted item cached briefly before hard delete

For permanent destructive actions, also consider confirmation for sensitive records.

Accessibility and Interaction Quality

Swipe actions should remain accessible to VoiceOver users through rotor actions and explicit action buttons where appropriate. Test on smaller devices to ensure action titles remain visible and do not truncate confusingly.

Animation quality matters too. Batch updates should remain short and deterministic to avoid jank in long lists.

Common Pitfalls

  • Deleting table rows without deleting matching model entries.
  • Mixing diffable data source updates with manual row deletion APIs.
  • Capturing stale index paths in async callbacks after data changes.
  • Ignoring server failure rollback when using optimistic deletion.
  • Shipping destructive swipe actions without undo or confirmation where needed.

Summary

  • UIKit provides built-in swipe-to-delete APIs for both basic and custom behaviors.
  • Keep model updates and table updates strictly synchronized.
  • Use UIContextualAction for modern custom swipe actions.
  • Handle async deletion carefully with rollback or delayed removal strategy.
  • Add undo and accessibility support for production-quality interaction.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.