Кэширование в Swift: Redis, Memcached и встроенные решения для iOS/macOS

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

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

Начать курс

Введение: Зачем нужно кэширование в Swift-приложениях?

Современные iOS и macOS приложения работают с большими объёмами данных: изображения, JSON-ответы от API, результаты вычислений. Без кэширования каждое обращение к данным приводит к повторной загрузке или пересчёту, что негативно сказывается на производительности, расходе трафика и времени отклика. Кэширование в Swift — это стратегия временного хранения часто используемых данных в быстром хранилище (оперативная память или локальный диск) для ускорения доступа.

В этой статье мы рассмотрим три основных подхода к кэшированию в экосистеме Swift:

  • Встроенные решения: NSCache и URLCache — лёгкие и эффективные инструменты для большинства задач.
  • Redis — мощный серверный кэш для распределённых систем.
  • Memcached — высокопроизводительная система кэширования в памяти.

Вы узнаете, как интегрировать каждый из этих инструментов в Swift-проект, увидите примеры кода и поймёте, какой вариант выбрать под конкретную задачу.

Встроенные решения: NSCache и URLCache

Apple предоставляет два мощных встроенных механизма кэширования, которые не требуют установки сторонних библиотек. Они идеально подходят для 90% задач в мобильной разработке.

NSCache — кэширование в памяти

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

import Foundation

// Создаём кэш для UIImage
let imageCache = NSCache<NSString, UIImage>()

// Функция загрузки изображения с кэшированием
func loadImage(from url: URL, completion: @escaping (UIImage?) -> Void) {
    // Проверяем кэш
    if let cachedImage = imageCache.object(forKey: url.absoluteString as NSString) {
        completion(cachedImage)
        return
    }
    
    // Загружаем данные
    URLSession.shared.dataTask(with: url) { data, response, error in
        guard let data = data, let image = UIImage(data: data) else {
            completion(nil)
            return
        }
        // Сохраняем в кэш
        imageCache.setObject(image, forKey: url.absoluteString as NSString)
        completion(image)
    }.resume()
}

Преимущества NSCache:

  • Автоматическая очистка при memory warning
  • Потокобезопасность без дополнительных блокировок
  • Возможность задать лимит по количеству объектов и общей стоимости

URLCache — кэширование HTTP-ответов

URLCache — это системный кэш для HTTP-запросов. Он сохраняет ответы сервера на диск и в память, автоматически управляя их сроком жизни на основе HTTP-заголовков (Cache-Control, Expires).

import Foundation

// Настройка URLCache (обычно в AppDelegate или SceneDelegate)
let cacheSize = 50 * 1024 * 1024 // 50 MB
let urlCache = URLCache(memoryCapacity: cacheSize, diskCapacity: cacheSize, diskPath: "myCache")
URLCache.shared = urlCache

// Пример запроса с кэшированием
let request = URLRequest(url: URL(string: "https://api.example.com/data")!)
URLSession.shared.dataTask(with: request) { data, response, error in
    // URLCache автоматически обработает кэширование
    // на основе заголовков Cache-Control
}.resume()

Когда использовать URLCache:

  • Для кэширования REST API ответов
  • Для статических ресурсов (изображения, файлы конфигурации)
  • Когда нужно соблюдать политику кэширования сервера

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

Redis — это высокопроизводительное хранилище данных в памяти, которое часто используется как кэш-сервер. Для Swift существует несколько клиентов, самый популярный — RediStack (на базе SwiftNIO). Redis идеально подходит для:

  • Кэширования сессий пользователей
  • Хранения результатов дорогих вычислений
  • Реализации очередей задач и pub/sub

Подключение RediStack

Добавьте зависимость в Package.swift:

// swift-tools-version:5.7
import PackageDescription

let package = Package(
    name: "MyApp",
    dependencies: [
        .package(url: "https://github.com/swift-server/RediStack.git", from: "1.4.0")
    ],
    targets: [
        .target(name: "MyApp", dependencies: ["RediStack"])
    ]
)

Пример работы с Redis на Swift

import RediStack
import NIOCore
import NIOPosix

// Создаём EventLoopGroup
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
let eventLoop = eventLoopGroup.next()

// Подключаемся к Redis
let connection = try RedisConnection.make(
    configuration: .init(hostname: "localhost", port: 6379),
    boundEventLoop: eventLoop
).wait()

// Сохраняем значение в кэш
try connection.set("user:123", to: "{\"name\": \"Иван\", \"age\": 30}").wait()

// Читаем значение
if let cachedData = try connection.get("user:123", as: String.self).wait() {
    print("Данные из кэша: \(cachedData)")
}

// Устанавливаем время жизни (TTL) — 60 секунд
try connection.expire("user:123", after: .seconds(60)).wait()

// Закрываем соединение
try connection.close().wait()
try eventLoopGroup.syncShutdownGracefully()

Важно: Redis — это сетевое решение, поэтому оно добавляет задержку на сетевое взаимодействие. Используйте его для серверных приложений (Vapor, Kitura) или для синхронизации кэша между устройствами.

Memcached — лёгкий и быстрый кэш

Memcached — это распределённая система кэширования в памяти. Она проще Redis, но невероятно быстрая и эффективная. Для Swift существует библиотека SwiftMemcached (или можно использовать C-клиент libmemcached через Swift Package Manager).

Установка SwiftMemcached

// Package.swift
dependencies: [
    .package(url: "https://github.com/OpenKitten/Memcached", from: "1.0.0")
]

Пример использования Memc

Блоги

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