Какие существуют способы кэширования объектов в iOS?

«Какие существуют способы кэширования объектов в iOS?» — вопрос из категории Управление памятью, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Выбор стратегии кэширования зависит от типа данных, объема, требований к производительности и персистентности.

Способ Назначение Плюсы Минусы
NSCache Временное хранение дорогих в создании объектов (изображения, результаты вычислений). Автоматически очищается при нехватке памяти. Потокобезопасен. Неперсистентный (данные теряются при перезапуске приложения).
Файловая система (Caches/) Кэширование больших данных (изображения, аудио, JSON). Большой объем. Контроль за сроком жизни файлов. Требуется ручное управление: инвалидация, очистка.
UserDefaults Хранение простых настроек и небольших данных пользователя. Простой API. Автоматическая персистентность. Не для больших или сложных данных. Медленнее in-memory кэшей.
Базы данных (Core Data, SQLite, Realm) Кэширование структурированных данных с сложными связями и запросами. Мощные запросы. Персистентность. Встроенные механизмы миграции. Overhead на настройку и поддержку.
Keychain Безопасное хранение чувствительных данных (токены, пароли). Высокая безопасность. Данные сохраняются между установками приложения. Сложный API. Медленный доступ.
In-memory (свойства, синглтоны) Глобальный доступ к данным в течение жизни процесса. Максимальная скорость доступа. Нет автоматического управления памятью. Риск утечек.

Практический пример NSCache:

// Объявление кэша
let imageCache = NSCache<NSString, UIImage>()

// Сохранение
func cacheImage(_ image: UIImage, forKey key: String) {
    imageCache.setObject(image, forKey: key as NSString)
}

// Получение
func getCachedImage(forKey key: String) -> UIImage? {
    return imageCache.object(forKey: key as NSString)
}

// Очистка при получении уведомления о нехватке памяти
NotificationCenter.default.addObserver(
    forName: UIApplication.didReceiveMemoryWarningNotification,
    object: nil,
    queue: .main
) { _ in
    imageCache.removeAllObjects()
}