Как реализовать кэширование статических файлов и где хранить данные?
Что проверяют
Знаете ли вы файловую систему песочницы iOS и разницу между кэшем в памяти и на диске. Следом обычно спрашивают, почему приложение раздувается в «Хранилище iPhone» и как ограничить размер кэша.
Как отвечать
Схема двухуровневая: сначала память, потом диск, потом сеть.
- память:
NSCacheвместо словаря. Он потокобезопасен, сам отдаёт объекты при нехватке памяти, лимиты задаются черезcountLimitиtotalCostLimit. Cost считайте по размеру декодированной картинки (ширина на высоту на 4 байта), а не по весу JPEG; Library/Caches: основное место для скачанных файлов. Не попадает в резервную копию, и система может его очистить при нехватке места, поэтому код обязан переживать исчезновение файла;Application Support: то, что нельзя потерять и что пользователь сам не видит. Попадает в бэкап, большие восстановимые файлы помечаютisExcludedFromBackupKey;Documents: файлы пользователя, их можно открыть в приложении «Файлы». Кэшу тут не место;tmp: кратковременное хранение, система чистит его без предупреждения.
Для сетевой статики вроде JSON и шрифтов часто хватает URLCache с ёмкостью, заданной через memoryCapacity и diskCapacity: он учитывает Cache-Control и ETag. Для картинок есть Kingfisher, Nuke, SDWebImage, где уже решены декодирование, отмена и лимиты.
Если пишете сами, имя файла делайте хешем URL (SHA-256 через CryptoKit), сохраняйте исходные байты ответа, а при превышении лимита удаляйте самые старые по дате доступа. Большие изображения уменьшайте через ImageIO (CGImageSourceCreateThumbnailAtIndex) до размера экрана.
Где спотыкаются
Пишут кэш в Documents. Он уезжает в бэкап iCloud и раздувает его, а за скачиваемый контент в этом каталоге приложение может получить отказ на ревью.
Пересжимают картинку через jpegData(compressionQuality: 1.0) перед записью. Файл растёт, прозрачность PNG теряется, хотя достаточно сохранить полученные Data.
Не ограничивают размер дискового кэша и не чистят его. Через месяц приложение занимает гигабайты, и пользователь удаляет его целиком.