Introducción: Por qué el caching es clave para el rendimiento de las aplicaciones Swift
En el desarrollo moderno con Swift, ya sea una aplicación iOS o una solución de servidor con Vapor, la velocidad de funcionamiento y la capacidad de respuesta de la interfaz dependen directamente de una gestión adecuada de los datos. El caching no es solo "recordar" resultados, sino toda una ciencia sobre cómo reducir el tiempo de acceso a los datos, disminuir la carga en la red y la base de datos, y garantizar un funcionamiento fluido incluso bajo cargas máximas.
A nivel avanzado, los desarrolladores de Swift se enfrentan a la elección: usar mecanismos integrados (NSCache, URLCache) o conectar sistemas externos como Redis y Memcached. Cada una de estas herramientas tiene su propia arquitectura y ámbito de aplicación. En este artículo, analizaremos cómo integrar y combinar estas soluciones de manera efectiva en el ecosistema Swift.
1. Soluciones integradas: NSCache y URLCache
1.1 NSCache — caché ligero para objetos
NSCache es un diccionario seguro para subprocesos integrado en Foundation. Es ideal para almacenar en caché objetos que son costosos de crear o cargar (por ejemplo, imágenes, resultados de cálculos complejos). La principal ventaja es la limpieza automática cuando falta memoria, algo crítico para aplicaciones móviles.
import Foundation
final class ImageCache { static let shared = ImageCache() private let cache = NSCache<NSString, UIImage>() private init() { cache.countLimit = 100 // Máximo 100 objetos cache.totalCostLimit = 50 * 1024 * 1024 // 50 MB } func getImage(for key: String) -> UIImage? { return cache.object(forKey: key as NSString) } func setImage(_ image: UIImage, for key: String, cost: Int? = nil) { if let cost = cost { cache.setObject(image, forKey: key as NSString, cost: cost) } else { cache.setObject(image, forKey: key as NSString) } } func removeImage(for key: String) { cache.removeObject(forKey: key as NSString) } func clearAll() { cache.removeAllObjects() }}Matices importantes:
countLimitytotalCostLimitson recomendaciones, no límites estrictos. El sistema decide cuándo eliminar objetos.- Las claves deben ser de tipo
NSString, noString(Swift las puentea automáticamente, pero es mejor convertirlas explícitamente). - No se debe usar
NSCachepara datos grandes que no caben en la memoria.
1.2 URLCache — caching de solicitudes de red
URLCache es un caché del sistema para solicitudes HTTP. Guarda automáticamente las respuestas del servidor (teniendo en cuenta los encabezados Cache-Control) y las devuelve sin contactar la red. La configuración permite controlar la cantidad de memoria y disco.
import Foundation
// Configuración de URLCache para toda la aplicaciónlet memoryCapacity = 20 * 1024 * 1024 // 20 MBlet diskCapacity = 100 * 1024 * 1024 // 100 MBlet cache = URLCache(memoryCapacity: memoryCapacity, diskCapacity: diskCapacity, diskPath: "myCache")URLCache.shared = cache
// Ejemplo de uso con URLSessionlet config = URLSessionConfiguration.defaultconfig.requestCachePolicy = .returnCacheDataElseLoad // Primero caché, luego redconfig.urlCache = cache
let session = URLSession(configuration: config)let url = URL(string: "https://api.example.com/data")!let task = session.dataTask(with: url) { data, response, error in // Los datos se tomarán del caché si existen y no están desactualizados}task.resume()Consejo avanzado: Para forzar la actualización del caché, use la política .reloadIgnoringLocalCacheData, y para la gestión manual, los métodos cachedResponse(for:) y storeCachedResponse(_:for:).