Кэширование в Swift (iOS/macOS): Redis, NSCache и другие решения

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

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

Начать курс

Кэширование в Swift (iOS/macOS): Redis и другие инструменты

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

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

NSCache — легковесный кэш в памяти

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

import Foundation

let imageCache = NSCache<NSString, UIImage>()

// Устанавливаем лимиты
imageCache.countLimit = 100    // Максимум 100 объектов
imageCache.totalCostLimit = 50 * 1024 * 1024 // 50 MB

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

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

Преимущества: простота, автоматическая очистка, поддержка стоимости объектов.

Недостатки: кэш только в памяти, нет персистентности.

URLCache — кэширование HTTP-запросов

URLCache автоматически кэширует ответы URLSession. Работает как в памяти, так и на диске. Настраивается глобально или для конкретной сессии.

import Foundation

// Настройка кэша 50 MB в памяти и 100 MB на диске
let cache = URLCache(memoryCapacity: 50 * 1024 * 1024,
                     diskCapacity: 100 * 1024 * 1024,
                     diskPath: "myCache")
URLCache.shared = cache

// Использование с URLSession
let config = URLSessionConfiguration.default
config.urlCache = cache
config.requestCachePolicy = .returnCacheDataElseLoad
let session = URLSession(configuration: config)

let request = URLRequest(url: URL(string: "https://api.example.com/data")!)
let task = session.dataTask(with: request) { data, response, error in
    // Данные будут автоматически кэшироваться
}
task.resume()

Управление политикой кэширования осуществляется через Cache-Control заголовки сервера или requestCachePolicy.

2. Файловое кэширование для офлайн-доступа

Когда требуется сохранить данные между запусками приложения, используется файловое кэширование в директории Caches. Удобно для JSON, изображений или сериализованных объектов.

import Foundation

class FileCache {
    private let fileManager = FileManager.default
    private lazy var cacheDirectory: URL = {
        let paths = fileManager.urls(for: .cachesDirectory, in: .userDomainMask)
        return paths[0].appendingPathComponent("DataCache", isDirectory: true)
    }()
    
    init() {
        try? fileManager.createDirectory(at: cacheDirectory, withIntermediateDirectories: true)
    }
    
    func save(data: Data, forKey key: String) {
        let fileURL = cacheDirectory.appendingPathComponent(key)
        try? data.write(to: fileURL)
    }
    
    func load(forKey key: String) -> Data? {
        let fileURL = cacheDirectory.appendingPathComponent(key)
        return try? Data(contentsOf: fileURL)
    }
    
    func clearAll() {
        try? fileManager.removeItem(at: cacheDirectory)
        try? fileManager.createDirectory(at: cacheDirectory, withIntermediateDirectories: true)
    }
}

3. Redis — распределённое кэширование для серверной части

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

Библиотека RediStack (Swift-NIO)

RediStack — асинхронный Redis-клиент на базе Swift-NIO. Подходит для macOS-приложений и серверного Swift (Vapor).

import RediStack
import NIOCore
import NIOPosix

// Подключение к Redis
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
let connection = try RedisConnection.make(
    configuration: .init(hostname: "localhost", port: 6379),
    boundEventLoop: eventLoopGroup.next()
).wait()

// Установка и получение значения
try connection.set("                    

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