Какие технологии использовать для загрузки массива изображений по URL в iOS
Что проверяют
Понимаете ли вы, что загрузка картинок это не один запрос, а связка из сети, декодирования, кэша и отмены. Следом почти всегда спрашивают, что будет с лентой на сотню ячеек при быстрой прокрутке.
Как отвечать
Начните с базы, а библиотеки подайте как готовую сборку тех же механизмов:
URLSession: сама загрузка. Со Swift Concurrency этоtry await URLSession.shared.data(from: url), а массив удобно грузить черезwithTaskGroup, собирая пары «индекс, картинка», чтобы порядок не зависел от того, кто ответил первым;- ограничение параллелизма: в группу добавляют не все задачи сразу, а несколько, и новую запускают после
await group.next(); - кэш:
URLCacheхранит сырые ответы по HTTP-заголовкам, а готовыеUIImageдержат вNSCache, который сам чистится при нехватке памяти; - даунсэмплинг: фото 4000×3000 в памяти занимает около 48 МБ, каким бы маленьким ни был JPEG. Уменьшайте до размера ячейки через ImageIO (
CGImageSourceCreateThumbnailAtIndex) илиpreparingThumbnail(of:), и не на главном потоке; - отмена: при переиспользовании ячейки старую задачу отменяют, иначе в неё прилетит чужая картинка;
- prefetching:
UICollectionViewDataSourcePrefetchingначинает загрузку до того, как ячейка появится на экране.
Дальше скажите, что в продакшене это обычно дают Kingfisher, SDWebImage или Nuke: кэш в памяти и на диске, даунсэмплинг, отмена. Alamofire сам по себе про сетевые запросы, для картинок у него есть отдельный модуль AlamofireImage. В SwiftUI есть AsyncImage, но своего кэша декодированных картинок у него нет, поэтому в длинных списках его обычно заменяют.
Где спотыкаются
Отдают UIImage(data:) прямо в ячейку. Декодирование полноразмерной картинки откладывается до первой отрисовки и происходит на главном потоке, отсюда рывки при прокрутке.
Забывают про отмену и переиспользование ячеек. Быстрая прокрутка превращается в мигание чужих картинок и лишний трафик.
Запускают загрузку всех URL разом и складывают картинки в словарь без лимита. На длинной ленте это предупреждения о памяти и завершение приложения системой, хотя хватило бы NSCache с totalCostLimit.