Какие сложности бывают с SwiftUI AsyncImage
Что проверяют
Работали ли вы с AsyncImage дальше демо-примера и понимаете ли, где он заканчивается. Следом обычно спрашивают: «А что вы используете в продакшене вместо него и почему?»
Как отвечать
AsyncImage появился в iOS 15 и хорош для простого случая: одна картинка по URL и заглушка на время загрузки. Проблемы начинаются в списках и галереях:
- кеширование: своего кеша у компонента нет. Он грузит через
URLSession.shared, и повторный показ зависит отURLCacheи заголовковCache-Controlсервера. В прокручиваемом списке картинки часто загружаются заново при каждом появлении ячейки; - нет контроля над запросом: свой
URLRequestили сессию не передать, значит, не добавить заголовок авторизации, таймаут или приоритет; - память: изображение декодируется в полном размере, даже если на экране миниатюра 60 на 60. Даунсэмплинга нет, и лента фотографий с камеры быстро раздувает память;
- отмена и повтор: когда ячейка уходит с экрана, загрузка отменяется, и в ряде версий iOS фаза приходит как
.failureс ошибкой отмены. Встроенного повтора нет, обычно пересоздают вью через.id(...); - модификаторы:
.resizable()и.aspectRatio(contentMode:)применяются кImageвнутри замыкания, а не к самомуAsyncImage.
Рабочий каркас: инициализатор с phase и разбор .empty, .success, .failure плюс @unknown default. Для анимации появления есть параметр transaction. Когда картинок много, берут Kingfisher, Nuke (LazyImage) или SDWebImageSwiftUI, либо пишут свой загрузчик: actor с NSCache, URLSession и уменьшением через ImageIO (CGImageSourceCreateThumbnailAtIndex).
Где спотыкаются
Утверждают, что AsyncImage кеширует картинки «как браузер». Кеш работает только через URLCache и только при правильных заголовках, гарантий нет.
Вешают .resizable() на сам AsyncImage и не понимают, почему код не компилируется: этот модификатор есть только у Image.
Показывают пользователю ошибку на каждую отменённую загрузку. Отмену при прокрутке нужно отличать от настоящего сетевого сбоя и не рисовать на её месте иконку поломки.