Caché en Swift (iOS/macOS): desde in-memory hasta Redis
En el desarrollo para iOS y macOS, el caché es una herramienta clave para acelerar las aplicaciones, reducir la carga del servidor y mejorar la experiencia del usuario. En este artículo, exploraremos los principales enfoques de caché en Swift: desde el simple NSCache hasta soluciones profesionales basadas en Redis y SQLite. Cada método tiene su ámbito de aplicación, y la elección correcta depende del tipo de datos, su volumen y los requisitos de persistencia.
1. NSCache — caché in-memory integrado
NSCache es un caché ligero y seguro para subprocesos, integrado en Foundation. Libera automáticamente la memoria cuando hay escasez de recursos, lo que lo hace ideal para almacenar en caché imágenes, datos de API y otros objetos temporales.
import Foundation
class ImageCache { private let cache = NSCache<NSString, UIImage>() func getImage(forKey key: String) -> UIImage? { return cache.object(forKey: key as NSString) } func setImage(_ image: UIImage, forKey key: String) { cache.setObject(image, forKey: key as NSString) } func removeImage(forKey key: String) { cache.removeObject(forKey: key as NSString) }}Ventajas:
- No requiere configuración — funciona "de fábrica".
- Gestiona automáticamente la memoria (elimina objetos en
didReceiveMemoryWarning). - Seguro para subprocesos.
Desventajas:
- Los datos se pierden al reiniciar la aplicación.
- No es adecuado para grandes volúmenes de datos (limitado por la RAM).
2. Core Data como caché persistente
Core Data se utiliza a menudo no solo como ORM, sino también como caché para datos estructurados. Esto es útil cuando se necesita guardar objetos complejos con relaciones y realizar filtrados.
import CoreData
class CoreDataCache { private let context: NSManagedObjectContext init(context: NSManagedObjectContext) { self.context = context } func cacheResponse(_ data: Data, forKey key: String) { let cached = CachedResponse(context: context) cached.key = key cached.data = data cached.timestamp = Date() try? context.save() } func getCachedResponse(forKey key: String) -> Data? { let fetchRequest: NSFetchRequest<CachedResponse> = CachedResponse.fetchRequest() fetchRequest.predicate = NSPredicate(format: "key == %@", key) fetchRequest.sortDescriptors = [NSSortDescriptor(key: "timestamp", ascending: false)] fetchRequest.fetchLimit = 1 guard let result = try? context.fetch(fetchRequest).first else { return nil } return result.data }}Cuándo usarlo:
- Los datos deben conservarse entre sesiones.
- Se necesita un filtrado complejo (por ejemplo, búsqueda de texto).
- El volumen de datos es moderado (hasta varios cientos de miles de registros).
3. Redis — caché del lado del servidor para Swift
Redis es un almacenamiento in-memory de alto rendimiento que funciona a través de la red. En el contexto de Swift (iOS/macOS), Redis se utiliza más a menudo en el lado del servidor (Vapor, Kitura) para almacenar en caché sesiones, resultados de consultas complejas y colas de tareas. Sin embargo, existen bibliotecas cliente que permiten conectarse a Redis directamente desde una aplicación móvil (por ejemplo, a través de RediStack).
import RediStack
final class RedisCache { private let connection: RedisConnection init(host: String, port: Int = 6379) async throws { self.connection = try await RedisConnection.connect( to: .init(hostname: host, port: port) ) }