Introducción: ¿por qué esta pregunta es tan popular?
\n\nCualquiera que haya escrito una aplicación para iOS al menos una vez se ha enfrentado a la tarea: «¿Cómo mostrar una imagen de internet en mi aplicación?» En Stack Overflow, la pregunta «Loading/Downloading image from URL on Swift» ha acumulado miles de visitas y cientos de respuestas. ¿Por qué? Porque es la base con la que se comienza a trabajar con la red en iOS. Y aunque parece que todo es simple —tomar la URL, descargar los datos, mostrar— en la práctica, los desarrolladores se enfrentan a muchos obstáculos: bloqueo del hilo principal, fugas de memoria, falta de caché y rendimiento lento.
\n\nEn este artículo analizaremos todas las formas populares de cargar imágenes desde una URL en Swift, responderemos preguntas frecuentes y mostraremos ejemplos de código que puedes usar directamente en tu proyecto.
\n\n1. La forma más simple: URLSession + Data
\n\nEmpecemos con lo clásico. En Swift, para descargar datos por red se usa URLSession. Así es como se ve el código mínimo funcional:
import UIKit\n\nfunc loadImage(from urlString: String, completion: @escaping (UIImage?) -> Void) {\n guard let url = URL(string: urlString) else {\n completion(nil)\n return\n }\n \n URLSession.shared.dataTask(with: url) { data, response, error in\n guard let data = data, error == nil else {\n completion(nil)\n return\n }\n let image = UIImage(data: data)\n DispatchQueue.main.async {\n completion(image)\n }\n }.resume()\n}\n\n\nImportante: pasamos el resultado al hilo principal mediante DispatchQueue.main.async. Si no haces esto, corres el riesgo de tener un crash al intentar actualizar la UI desde un hilo secundario.
Cómo usarlo:
\n\nloadImage(from: "https://example.com/image.jpg") { image in\n self.imageView.image = image\n}\n\n\nEste método es adecuado para proyectos simples donde necesitas cargar 1-2 imágenes. Pero para aplicaciones reales no es óptimo: no hay almacenamiento en caché, no hay manejo de errores, y al desplazar una tabla todo se ralentizará.
\n\n2. Enfoque moderno: async/await (Swift 5.5+)
\n\nA partir de iOS 15 y Swift 5.5, es posible escribir código asíncrono en estilo imperativo con async/await. La carga de imágenes se vuelve elegante y legible:
import UIKit\n\nfunc loadImageAsync(from urlString: String) async throws -> UIImage? {\n guard let url = URL(string: urlString) else {\n throw URLError(.badURL)\n }\n \n let (data, _) = try await URLSession.shared.data(from: url)\n return UIImage(data: data)\n}\n\n\nUso en SwiftUI:
\n\nstruct ContentView: View {\n @State private var image: UIImage?\n \n var body: some View {\n VStack {\n if let image = image {\n Image(uiImage: image)\n .resizable()\n .scaledToFit()\n } else {\n ProgressView()\n }\n }\n .task {\n do {\n image = try await loadImageAsync(from: "https://example.com/image.jpg")\n } catch {\n print("Error de carga: \\(error)")\n }\n }\n }\n}\n\n\n¿Por qué es genial? El código se vuelve lineal, sin closures anidados, y es fácil de leer. Sin embargo, el problema del almacenamiento en caché persiste: seguimos descargando la imagen cada vez desde cero.
\n\n3. Almacenamiento en caché: cómo no acabar con el tráfico del usuario
\n\nLa pregunta más frecuente que hacen los principiantes es: «¿Por qué mis imágenes se descargan cada vez que desplazo la tabla?» La respuesta es simple: no estás usando caché.
\n\nEn iOS existe URLCache integrado, que se puede configurar para URLSession. Pero para imágenes es mejor usar NSCache — que automá