Кэширование в Swift (iOS/macOS): Redis, NSCache и Core Data

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Кэширование в Swift (iOS/macOS): Redis и альтернативы

Кэширование — один из ключевых механизмов оптимизации производительности мобильных и десктопных приложений на Swift. Оно позволяет сократить время загрузки данных, снизить нагрузку на сервер и улучшить пользовательский опыт. В этой статье мы рассмотрим основные инструменты кэширования для iOS и macOS: от встроенных решений (NSCache, URLCache) до интеграции с внешними системами (Redis) и постоянными хранилищами (Core Data).

1. Встроенные механизмы кэширования

1.1 NSCache — быстрый in-memory кэш

NSCache — это потокобезопасный, автоматически очищаемый кэш, идеально подходящий для временного хранения объектов, которые можно восстановить (например, изображения или результаты парсинга).

import Foundation

let imageCache = NSCache<NSString, UIImage>()

func loadImage(from url: URL, completion: @escaping (UIImage?) -> Void) {
    let cacheKey = url.absoluteString as NSString

    // Проверяем кэш
    if let cachedImage = imageCache.object(forKey: cacheKey) {
        completion(cachedImage)
        return
    }

    // Загружаем данные
    URLSession.shared.dataTask(with: url) { data, _, _ in
        guard let data = data, let image = UIImage(data: data) else {
            completion(nil)
            return
        }
        // Сохраняем в кэш
        imageCache.setObject(image, forKey: cacheKey)
        completion(image)
    }.resume()
}

Особенности:

  • Автоматически удаляет объекты при нехватке памяти (поддерживает countLimit и totalCostLimit).
  • Идеален для кэширования загруженных изображений, JSON-ответов API.
  • Не сохраняет данные между запусками приложения.

1.2 URLCache — системный кэш HTTP-запросов

URLCache предоставляет прозрачное кэширование сетевых запросов на уровне системы. Поддерживает дисковое и оперативное хранение.

let cache = URLCache(memoryCapacity: 50 * 1024 * 1024,   // 50 MB
                     diskCapacity: 200 * 1024 * 1024,     // 200 MB
                     diskPath: "myCache")
URLCache.shared = cache

// Пример запроса с кэшированием
let request = URLRequest(url: URL(string: "https://api.example.com/data")!,
                         cachePolicy: .returnCacheDataElseLoad,
                         timeoutInterval: 30)
URLSession.shared.dataTask(with: request) { data, response, error in
    // Данные будут автоматически закэшированы
}.resume()

Этот метод отлично работает для статичных ресурсов (изображения, файлы конфигураций), но не подходит для динамических данных, требующих актуальности.

2. Постоянное кэширование с Core Data

Если требуется сохранять данные между сессиями приложения, используйте Core Data или SQLite (через GRDB.swift). Ниже пример простого кэша на Core Data:

import CoreData

class CacheManager {
    static let shared = CacheManager()
    private let context: NSManagedObjectContext

    private init() {
        // Настройка Core Data stack (упрощено)
        let container = NSPersistentContainer(name: "CacheModel")
        container.loadPersistentStores { _, error in
            if let error = error { fatalError("Core Data error: \(error)") }
        }
        context = container.viewContext
    }

    func save(data: Data, forKey key: String) {
        let entity = CachedItem(context: context)
        entity.key = key
        entity.data = data
        entity.timestamp = Date()
        try? context.save()
    }

    func load(forKey key: String) -> Data? {
        let fetch: NSFetchRequest<CachedItem> = CachedItem.fetchRequest()
        fetch.predicate = NSPredicate(format: "key == %@", key)
        let result = try? context.fetch(fetch)
        return result?.first?.data
    }
}

Рекомендация: Для кэширования больших объёмов данных (базы новостей, каталоги товаров) используйте Core Data с индексами и лимитами по времени жизни записи.

3. Интеграция с Redis (серверное кэширование)

Для приложений, взаимодействующих с сервером, часто требуется распределённый кэш. Redis — идеальный выбор. На iOS/macOS доступны клиенты:

  • RediStack — асинхронный Swift-клиент для Redis (на базе NIO).
  • SwiftRedis — простой синхронный клиент.

Пример использования RediStack (через SPM):

import RediStack

let eventLoop = MultiThreadedEventLoopGroup(numberOfThreads: 1).                    

Рекомендаций