Contenido del curso
Estructura de un Proyecto con MVVM
Operaciones CRUD en un proyecto con MVVM
- 11

Función addTodo con Core Data en SwiftUI
19:47 min - 12

Funcionalidades básicas para gestionar tareas en SwiftUI
14:30 min - 13

Listado y detalle de notas en SwiftUI
22:35 min - 14

Editar todos con SwiftUI y Core Data
13:41 min - 15

Archivar tareas en SwiftUI con Core Data
15:28 min - 16

Cómo desarchivar tareas con unarchiveTodo
03:25 min - 17

Eliminar un to do definitivamente con Core Data
04:15 min - 18

Marcar tareas completadas en SwiftUI
20:50 min - 19

Creación de Vistas Amigables en SwiftUI para Aplicaciones de Tareas
19:52 min
Clean Architecture
- 20

Qué es Clean Architecture y por qué supera a MVVM
05:52 min - 21

Estructura y Ventajas de la Clean Architecture
03:47 min - 22

Estructura de proyecto iOS con Clean Architecture
06:01 min - 23

Mapeo de JSON a structs Swift con Codable
09:10 min - 24

Capa de datos con Clean Architecture en Swift
30:54 min - 25

Casos de uso en la capa de dominio Swift
09:35 min - 26

Capa de presentación con MVVM en SwiftUI
15:37 min - 27

Navegación y detalle con Clean Architecture en SwiftUI
21:54 min
MVVM y Clean Architecture
Cómo conectar CoreData y Combine en MVVM
Resumen
Construir un ViewModel reactivo en Swift te permite conectar el modelo de datos con la interfaz sin actualizar nada a mano. Aquí verás cómo armar un ToDoViewModel usando Combine y Core Data dentro de una arquitectura MVVM, paso a paso, para que cualquier cambio en tus tareas se refleje al instante en la vista.
Por qué usar Combine como puente entre vista y modelo
Combine es el framework de Apple que maneja datos de forma reactiva. En lugar de refrescar la pantalla manualmente cada vez que cambia una tarea, suscribes la vista a un dato observable y las actualizaciones ocurren solas [00:25].
En una arquitectura MVVM tienes tres capas: el modelo (los datos), la vista (lo que ves) y el view model (el intermediario que comunica ambos). Combine vive justo en ese intermediario.
¿Qué hace Combine en un ViewModel? Permite que las propiedades marcadas como publicadas notifiquen a la vista cualquier cambio, sin que tú escribas código extra para refrescar la UI.
Qué importaciones necesita el ViewModel
Dentro del archivo ToDoViewModel.swift necesitas tres importaciones clave [01:30]:
- Foundation: herramientas base de Swift.
- CoreData: el framework para almacenar datos de forma local.
- Combine: para manejar datos reactivos.
La clase se declara como public final class ToDoViewModel: ObservableObject. Ese conformismo a ObservableObject es lo que permite que las vistas se suscriban a los cambios de sus propiedades publicadas.
Cómo declarar propiedades publicadas y persistencia
La propiedad central del ViewModel es la colección de tareas. Se declara como un array vacío de tipo ToDoEntity, que es la entidad de Core Data donde vive la estructura de cada tarea [02:50].
Para que cualquier cambio en esa lista se propague automáticamente a la vista, se anota con @Published. Esa anotación es justo lo que conecta Combine con SwiftUI: si agregas, eliminas o modificas un to-do, la vista se redibuja sola.
swift @Published var todos: [ToDoEntity] = [] var cancellables: Set<AnyCancellable> = [] let storeContainer: NSPersistentContainer = ToDoPersistentManager.sharedContainer
La variable cancellables es un Set<AnyCancellable> y sirve para evitar fugas de memoria, cancelando suscripciones cuando ya no las necesitas [04:20]. El storeContainer es de tipo NSPersistentContainer y accede al contenedor compartido del ToDoPersistentManager, que es donde vive la base de datos local.
Cómo cargar las tareas al inicializar
En el init() se llama a fetchTodos(), así cuando creas una instancia del ViewModel ya tienes todas las tareas cargadas [05:50].
La función fetchTodos usa NSFetchRequest<ToDoEntity> para consultar Core Data. Para ordenar los resultados se usa un NSSortDescriptor con la key date y ascending: true, lo que devuelve las tareas ordenadas cronológicamente [07:00].
También se asigna request.returnsObjectsAsFaults = false para evitar cargar objetos fallidos y obtener acceso completo a los datos. Todo esto va envuelto en un do-catch que imprime un mensaje si falla la recuperación.
swift let request: NSFetchRequest<ToDoEntity> = ToDoEntity.fetchRequest() let sortDescriptor = NSSortDescriptor(key: "date", ascending: true) request.sortDescriptors = [sortDescriptor] request.returnsObjectsAsFaults = false do { todos = try storeContainer.viewContext.fetch(request) } catch { print("Error al recuperar todos") }
Qué métodos auxiliares necesita el ToDoViewModel
Más allá de listar tareas, el ViewModel necesita métodos para guardar, validar y localizar elementos.
El método privado saveData() llama a storeContainer.viewContext.save() dentro de un do-catch y luego ejecuta fetchTodos() para refrescar la lista [10:00]. Como todos está marcado con @Published, ese refresh se propaga solo a la vista.
¿Por qué llamar a fetchTodos después de guardar? Porque al modificar la propiedad publicada, Combine notifica a la vista y el cambio aparece sin código adicional.
Cómo encontrar el índice de una tarea
La función privada getTodoIndex(of:) recibe un ToDoEntity y devuelve el índice donde se encuentra dentro del array todos [11:40]. Usa firstIndex(where:) comparando el id del elemento con el del parámetro.
Si no lo encuentra, devuelve nil. Si lo encuentra, devuelve un entero con la posición.
Cómo validar el texto antes de guardar
La función pública validateInputs(of text: String) -> Bool aplica trimmingCharacters(in: .whitespaces) para eliminar espacios en blanco y luego cuenta los caracteres restantes [13:10]. Si el conteo es mayor a cero, retorna true; en caso contrario, false.
Esta validación es útil sobre todo para el título de la tarea, evitando que entren cadenas vacías o solo con espacios.
Qué funciones públicas expone el ViewModel
Para cubrir altas, bajas y modificaciones, el ViewModel declara varias funciones públicas que se implementarán después [14:30]:
addTodo: crea una tarea nueva.updateTodo: actualiza el título o descripción.updateTodoStatus: cambia el estado entre completado y no completado.deleteTodo: elimina una tarea.archiveTodo: archiva una tarea.unarchiveTodo: la desarchiva.
Con este conjunto, el ViewModel cubre todo el ciclo de vida de una tarea dentro de la base de datos local.
La pieza que falta es conectar la vista con este ViewModel para consumir los datos de forma reactiva. ¿Cómo crees que SwiftUI debería suscribirse a @Published para mostrar la lista? Cuéntame en los comentarios.