How to insert new cell into UITableView in Swift
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Inserting a row into a UITableView is straightforward once you remember the core rule: update your data model first, then tell the table view which row was inserted. Most crashes in this area happen because the array and the visible rows get out of sync.
Set Up a Table with a Backing Array
The table view does not store your business data for you. A simple array is usually the source of truth for row content.
This controller already displays rows. The only missing piece is the insertion logic.
Insert a New Row Correctly
When the user taps the add button, append or insert into the array first. Then call insertRows(at:with:) using the same index.
This example inserts at the top of the list. If you want to add to the end instead, use items.append(newItem) and set the row to items.count - 1 after the append.
UITableView animates the insertion and asks the data source for the new cell. Because the array already contains the item, cellForRowAt can return the correct content without inconsistency.
Use Batch Updates for Multiple Changes
If you insert several rows or combine insertions with deletions, wrap the changes in a batch update. That keeps the animation and index math consistent.
Batch updates are especially useful when the visible result depends on multiple coordinated changes.
Common Pitfalls
The most frequent mistake is calling insertRows before updating the data array. The table view then believes there is an extra row, but the data source still reports the old count. That mismatch often triggers the classic "invalid number of rows" crash.
Another issue is computing the wrong index path. If you insert at the top, the index path must be row 0. If you append, the new row must be the last valid index after the array has changed.
Reloading the entire table with reloadData() also works, but it gives up the insertion animation and can be less efficient. Use it when the whole table truly changed, not as a substitute for correct row insertion logic.
Finally, make sure UI updates happen on the main thread. If data arrives from a network request or background queue, dispatch the insert back to DispatchQueue.main.async before touching UITableView.
Summary
- Keep a backing array or other data source as the single source of truth.
- Insert into the model first, then call
insertRows(at:with:). - Use matching index paths so the table view and data source stay consistent.
- Prefer batch updates when applying several row changes together.
- Touch
UITableViewonly on the main thread to avoid race conditions and crashes.

