Как правильно возвращать количество элементов массива в методе UITableView
Что проверяют
Вопрос выглядит тривиальным, return items.count, но проверяют, понимаете ли вы, что таблица и источник данных обязаны быть синхронизированы в каждый момент. Следом почти всегда спрашивают про краш NSInternalInconsistencyException при вставке строк и про diffable data source.
Как отвечать
Базовая часть: tableView(_:numberOfRowsInSection:) из UITableViewDataSource возвращает количество элементов модели для конкретной секции. При нескольких секциях это sections[section].items.count, а число секций задаёт numberOfSections(in:), по умолчанию 1. Метод вызывается часто, поэтому никаких вычислений и фильтраций в нём: только чтение готового массива.
Главное правило: numberOfRowsInSection и cellForRowAt читают один и тот же источник. Если включён поиск, оба метода берут отфильтрованный массив, иначе items[indexPath.row] вылетит с Index out of range.
Изменение данных:
- полная перезагрузка: меняете массив и вызываете
reloadData(). Просто, но без анимаций и со сбросом состояния ячеек; - точечные изменения: внутри
performBatchUpdates(_:completion:)сначала меняете модель, затем вызываетеinsertRows(at:with:)илиdeleteRows(at:with:). Таблица сверяет новое количество строк со старым плюс вставленные минус удалённые и при расхождении падает сInvalid update: invalid number of rows in section; UITableViewDiffableDataSource(iOS 13+): вы собираетеNSDiffableDataSourceSnapshotи вызываетеapply, количество строк и анимации система считает сама, и краши рассинхронизации исчезают.
Все изменения массива, который читает таблица, делайте на главном потоке.
Где спотыкаются
Вызывают insertRows до того, как добавили элемент в массив. Таблица спрашивает numberOfRowsInSection, получает старое число и падает с NSInternalInconsistencyException.
Обновляют массив из колбэка сети на фоновом потоке. Таблица в этот момент может читать его с главного, и падения становятся случайными и плохо воспроизводимыми.
Возвращают количество из одного массива, а ячейки строят по другому, например по полному списку при активном поиске. Счётчик и данные расходятся, и приложение падает при первой прокрутке.