Contenido del curso

Operaciones CRUD en un proyecto con MVVM

Capa de presentación con MVVM en SwiftUI

Resumen

La capa de presentación en Clean Architecture combina la estructura visual de MVVM con la separación de responsabilidades de las capas de datos y dominio. Aquí construyes los view models que conectan tus vistas SwiftUI con los casos de uso, manteniendo el código desacoplado y testeable.

Por qué MVVM forma parte de Clean Architecture

MVVM y Clean Architecture no compiten, se complementan. MVVM se enfoca en la parte visual con tres piezas: model, view y view model. Pero su model es genérico y no distingue de dónde vienen los datos.

Clean Architecture amplía ese concepto y separa el model en dos capas dedicadas: una de datos y otra de dominio. Así puedes organizar mejor la información que tu app necesita procesar [00:31].

¿Qué hace un view model en SwiftUI? Es una clase que expone datos observables a la vista y encapsula la lógica de carga. La vista se actualiza automáticamente cuando el view model publica cambios.

Cómo se construye un view model con datos observables

El primer paso es crear un archivo PopularShowsViewModel dentro del directorio de presentación. La clase se declara como final class e importa SwiftUI para usar las anotaciones de observación.

Dentro de la clase declaras una propiedad publicada con la anotación @Published, que en el ejemplo es un arreglo shows de tipo TVShow inicializado vacío. Esa propiedad publicada es la que las vistas de SwiftUI van a observar para reaccionar ante cualquier cambio [02:30].

Cómo conectar la capa de presentación con la de dominio

El view model nunca debe conocer la implementación concreta de los casos de uso, solo su abstracción. Por eso declaras una propiedad privada que dependa del protocolo, no de la clase concreta.

  • Declaras private let getPopularTVShowsUseCase: GetPopularTVShowsUseCaseProtocol.
  • Creas un init que reciba esa dependencia como parámetro.
  • Asignas un valor por defecto inyectando la clase concreta GetPopularTVShowsUseCase().

Esto demuestra el principio de inyección de dependencias, clave para mantener las clases desacopladas. Al no estar fuertemente enlazadas, puedes sustituir implementaciones reales por mocks durante las pruebas [03:48].

Cómo cargar los datos desde el caso de uso

La función loadPopularShows encapsula la lógica de carga y cumple el principio de responsabilidad única. Dentro lanzas un Task con un bloque do/catch para capturar errores.

En el do ejecutas try await getPopularTVShowsUseCase.execute() y guardas el resultado en una constante. Como esa propiedad publicada actualiza la UI, debes asignarla en el hilo principal usando await MainActor.run { self.shows = shows }. Así garantizas que SwiftUI reaccione correctamente a los cambios [05:48].

¿Para qué sirve MainActor.run en SwiftUI? Asegura que la actualización de propiedades publicadas ocurra en el hilo principal, que es donde SwiftUI necesita aplicar los cambios visuales sin bloquear ni provocar advertencias.

Cómo enlazar la vista SwiftUI con el view model

Dentro de la carpeta views creas un nuevo archivo desde el template SwiftUI view con el nombre PopularShowsView. La vista necesita una referencia al view model y la declaras con la anotación @StateObject.

swift @StateObject private var viewModel = PopularShowsViewModel()

En el body colocas un List que itera sobre viewModel.shows usando id: \.id y muestra cada programa con un Text(show.name). Para disparar la carga inicial, agregas .onAppear con un Task que llame a viewModel.loadPopularShows() [07:43].

Cómo apuntar la app a la vista correcta

Al ejecutar la app por primera vez aparece la pantalla con un ícono y el texto Hola, mundo. Eso ocurre porque el punto de entrada en SwiftUI es la estructura que hereda de App, y dentro del WindowGroup se está cargando ContentView.

La solución es abrir ContentView y reemplazar la imagen por una llamada a PopularShowsView(). Al ejecutar de nuevo, la lista devuelve nombres reales de programas en español como Papás por conveniencia o High Promesa [09:55].

¿Qué es @StateObject en SwiftUI? Es la anotación que crea y mantiene viva una instancia de un view model mientras la vista existe. Garantiza que los datos observables sobrevivan a redibujados.

Qué logra esta arquitectura en tu app iOS

Con estos pasos quedan enlazadas las tres capas: presentación, dominio y datos. La vista llama al view model, el view model ejecuta el caso de uso del dominio y este consulta el repositorio que vive en la capa de datos.

Desde aquí puedes mejorar la vista sin tocar la lógica: agregar márgenes, cambiar el Text por un título con imagen del programa o aplicar estilos personalizados. La estructura permanece intacta porque cada capa cumple una sola responsabilidad.

¿Qué cambios harías tú al diseño de la lista para mostrar mejor cada programa de televisión?