Contenido del curso

Operaciones CRUD en un proyecto con MVVM

Casos de uso en la capa de dominio Swift

Resumen

Definir casos de uso en la capa de dominio te permite separar el comportamiento de tu aplicación iOS de la lógica de datos, siguiendo Clean Architecture. Aquí aprendes a crear use cases en Swift para consumir un API de programas de televisión, aplicando inyección de dependencias y el principio de inversión.

Qué es un caso de uso y por qué va en la capa de dominio

Un caso de uso describe una acción concreta que tu aplicación puede ejecutar. No mezcla detalles de red ni de almacenamiento; solo orquesta la lógica de negocio.

En la app que estamos construyendo, hay dos comportamientos claros: obtener el listado de programas populares y obtener el detalle de uno específico. Cada uno se traduce en un archivo separado dentro de la capa de dominio.

¿Qué es un caso de uso en Clean Architecture? Es una clase que representa una acción única de la aplicación, como obtener programas populares. Vive en la capa de dominio y delega la obtención de datos al repositorio.

Cómo defino el protocolo de un Use Case en Swift

El primer archivo se llama GetPopularTVShowsUseCaseProtocol [01:25]. Dentro declaras un protocol con el mismo nombre y una función asíncrona que retorna un arreglo de TVShow.

swift protocol GetPopularTVShowsUseCaseProtocol { func execute() async throws -> [TVShow] }

Esta declaración no implementa nada. Solo define el contrato: una función execute marcada como async throws que devuelve [TVShow]. Así cualquier clase que adopte el protocolo sabe qué firma debe respetar.

Cómo implemento el caso de uso con inyección de dependencias

La implementación vive en la misma capa, pero como una final class que adopta el protocolo. Aquí aplicas el principio de inversión de dependencias: la clase depende de la abstracción TVShowRepository, no de su implementación concreta.

swift final class GetPopularTVShowsUseCase: GetPopularTVShowsUseCaseProtocol { private let repository: TVShowRepository

init(repository: TVShowRepository = TVShowRepositoryImpl()) { self.repository = repository } func execute() async throws -> [TVShow] { try await repository.fetchPopularTVShows() }

}

Fíjate en el detalle del init: el parámetro recibe un TVShowRepository (el protocolo) y por defecto se le asigna una instancia de TVShowRepositoryImpl. Esto te permite inyectar mocks en pruebas sin tocar la lógica.

¿Por qué inyectar el repositorio en lugar de instanciarlo dentro? Porque te da control sobre la dependencia. Puedes sustituirla por una versión falsa al testear, sin que la clase sepa de la implementación real.

Qué cuidados hay con el nombre execute

Un error común es declarar execute en el protocolo y escribir executes en la clase, o al revés. Swift no detectará el método como implementación del protocolo y lanzará error de compilación [05:30]. Revisa que ambos nombres coincidan exactamente.

Cómo creo el caso de uso para el detalle de un programa

El segundo archivo, GetTVShowDetailsUseCaseProtocol, sigue la misma estructura, pero la función execute recibe un identificador entero y devuelve un objeto TVShowDetails.

swift protocol GetTVShowDetailsUseCaseProtocol { func execute(id: Int) async throws -> TVShowDetails }

final class GetTVShowDetailsUseCase: GetTVShowDetailsUseCaseProtocol { private let repository: TVShowRepository

init(repository: TVShowRepository = TVShowRepositoryImpl()) { self.repository = repository } func execute(id: Int) async throws -> TVShowDetails { try await repository.fetchTVShowDetails(id: id) }

}

La diferencia clave es el parámetro id: Int que viaja desde la vista hasta el repositorio, atravesando el caso de uso sin transformaciones. El use case actúa como puente delgado.

¿Qué hace el método execute en un Use Case? Llama al repositorio correspondiente y retorna el resultado. No procesa datos ni maneja red; solo orquesta la acción.

Qué responsabilidades quedan separadas entre capas

Con estos dos archivos, la capa de dominio queda lista. La división de responsabilidades es:

  • La capa de datos maneja la comunicación con el API y el mapeo de modelos.
  • La capa de dominio expone casos de uso y depende solo de abstracciones.
  • La capa de presentación, que sigue pendiente, consumirá estos use cases desde las vistas o view models.

Esta separación te permite cambiar la fuente de datos sin tocar el dominio, y modificar la lógica de negocio sin alterar la UI.

¿Tú cómo estás organizando tus use cases en proyectos Swift? Cuéntame en los comentarios si prefieres una clase por acción o agrupar varias en un solo archivo.