Кэширование в 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).