Какие существуют способы кэширования объектов в 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()
}

Ответ 18+ 🔞

А, ну вот, опять про кэширование, да? Ну, слушай, это как с холодильником разобраться — куда что положить, чтобы потом не искать полдня, а то и не найти вообще, блядь.

Смотри, у тебя есть куча вариантов, и каждый — как отдельный персонаж в этой ебучей драме под названием «Оптимизация приложения».

NSCache — это как твой карманный алкоголик. Быстро достал, быстро выпил, а если денег нет — он сам исчезнет, не будет тебе мозги выносить. Идеально для картинок или каких-то тяжёлых объектов, которые жрут память. Плюс — сам сбрасывается, когда система орёт «ПАМЯТИ НЕТ, СУКА!». Минус — закрыл приложение, и всё, пиздец, пусто.

Файловая система (папка Caches/) — это уже типа кладовка в гараже. Свалил туда гигабайты фоток, JSON'ов, аудио — и пусть лежат. Объём большой, контролируешь сроки годности сам. Но если не убираться — зарастёт хламом, и приложение будет весить как чугунный мост, ёпта.

UserDefaults — ну это твоя тумбочка у кровати. Кинул туда настройки, какую-то мелкую хуйню, и они всегда под рукой. Просто, удобно, но попробуй запихни туда диван — не влезет, и доставать будет медленно. Не для больших данных, чисто для ключей-флажков.

Базы данных (Core Data, SQLite, Realm) — это уже целый склад с логистикой. Нужно хранить структурированную хуйню, где всё связано, и ты постоянно что-то ищешь, фильтруешь? Вот оно. Мощно, персистентно, но, блядь, настроить эту систему — это как собрать мебель из Икеи без инструкции. Головняк гарантирован.

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()
}

Вот и вся магия. Выбирай инструмент по задаче, а не потому что он модный. Иначе получишь архитектурный пиздец, который потом разгребать будут твои же коллеги, проклиная всё на свете. Удачи, епта!