Как обрабатывать пустой массив продуктов в iOS
Что проверяют
Отличаете ли вы «данных нет» от «данные ещё грузятся» и «загрузка упала» и умеете ли показать каждое состояние без костылей. Следом часто спрашивают, где такая логика должна жить и как её протестировать.
Как отвечать
Главная мысль: пустой массив это нормальный результат, а не ошибка. Сложность не в isEmpty, а в том, что по одному массиву нельзя понять, что показывать. Поэтому состояние экрана описывают перечислением:
enum ViewState {
case loading
case loaded([Product])
case empty
case failed(Error)
}Решение «пусто или нет» принимает ViewModel или Presenter, а экран только рендерит состояние. Такую логику легко покрыть юнит-тестом без UI.
Как показать пустое состояние:
- SwiftUI:
ContentUnavailableViewс иконкой, текстом и кнопкой действия, для пустого поиска есть готовыйContentUnavailableView.search(iOS 17 и новее); - UIKit:
UIContentUnavailableConfigurationчерез свойствоcontentUnavailableConfigurationу контроллера (тоже iOS 17), для старых версийbackgroundViewуUITableViewилиUICollectionView; - текст по контексту: «ничего не нашлось по запросу» и «каталог пуст» это разные экраны, и в первом полезна кнопка сброса фильтров.
Про сам массив: вместо products[0] берите products.first, он вернёт опционал, а для отсутствующего в JSON ключа используйте decodeIfPresent(...) ?? [], чтобы nil и пустой список не ломали экран по-разному. При пагинации пустая следующая страница означает конец списка, а не пустой каталог.
Где спотыкаются
Считают пустой ответ ошибкой и показывают алерт «продукты не найдены». Для пользователя это выглядит как сбой там, где всё работает.
Добавляют UILabel через addSubview при каждом обновлении и не убирают, когда данные появились. Лейблы копятся поверх таблицы.
Показывают пустое состояние до окончания загрузки: на долю секунды мелькает «ничего нет», а потом появляется список. Ради этого и нужно отдельное состояние loading.