Al crear una app iOS, tarde o temprano aparece esta situación: una pantalla mezcla los estados de carga, éxito, error y datos vacíos.
Gestionar montones de variables Bool como isLoading, hasError y isEmpty se convierte en un infierno a medida que aumentan.
Un estado en carga con el error también en true. No tiene sentido lógico, pero el código puede crear fácilmente esa combinación.
La conclusión es esta: puedes organizarlo mucho mejor creando una FSM con un solo enum de Swift, sin el patrón State.
Hoy veremos, con código, cómo salir del infierno de los Bool.
¿Qué es una máquina de estados (FSM)?
No hace falta complicarlo.
Una máquina de estados, FSM (Finite State Machine), significa que el número de estados posibles está definido y que las transiciones siguen reglas establecidas.
Piensa en un semáforo.
Verde → amarillo → rojo. Solo cambia en ese orden; nunca salta directamente de verde a rojo.
Las pantallas de una app funcionan igual. Pasan de 로딩 → 성공 o de 로딩 → 실패; no debería existir un estado que sea 성공 y 로딩 a la vez.
Pero al usar varias variables Bool, el código puede crear estados que no deberían existir.
Eso es precisamente lo que evita enum.
Cómo crear una máquina de estados con Swift enum
Los enum de Swift no son solo listas de constantes.
La clave es que cada case puede contener un valor (associated value). Así, un solo enum puede contener el estado y los datos.
Definí los estados de la pantalla así.
enum LoadState {
case idle // Aún no se ha hecho nada
case loading // Cargando
case loaded([Item]) // Éxito, con los datos
case failed(Error) // Error, con el error
}
Como ves, loaded contiene un array de elementos y failed contiene un error.
Si hay éxito, siempre hay datos; si hay error, siempre hay un error. Un estado extraño como éxito sin datos ni siquiera puede crearse.
En la vista, solo tienes que observar este único estado y renderizar la pantalla.
switch state {
case .idle: EmptyView()
case .loading: ProgressView()
case .loaded(let items): ItemList(items)
case .failed(let error): ErrorView(error)
}
Como switch obliga a gestionar todos los case, el compilador avisa enseguida si añades un estado y dejas algún caso sin tratar.
Es una gran ventaja: el compilador detecta los estados omitidos, no las personas.
¿Se puede prescindir del patrón State?
Los libros de orientación a objetos suelen enseñar la gestión de estados mediante el patrón State.
Se crea una clase por estado, se agrupan mediante un protocolo y se coloca la lógica de transición en cada clase.
Sinceramente, para gestionar estados de pantalla suele ser excesivo.
Comparé brevemente ambos enfoques. (Según mi experiencia profesional en 2026)
| Elemento | enum FSM | Patrón State |
|---|---|---|
| Número de archivos/tipos | Un enum | Una clase por estado |
| Prevención de estados omitidos | Un switch obligatorio permite que el compilador los detecte | Hay que comprobarlo manualmente |
| Inclusión de datos | Natural mediante associated value | Se gestiona aparte mediante propiedades |
| Escala adecuada | Unos 3–7 estados | Cuando la lógica de cada estado es muy compleja |
Si el número de estados es razonable y su lógica no es demasiado pesada, una FSM con enum es mucho más ligera y segura.
En cambio, si cada estado incluye decenas de líneas de comportamiento complejo, conviene considerar el patrón State o separar la lógica en objetos independientes.
No hay una única respuesta correcta.
¿Cómo se gestionan las transiciones de estado?
Podrías preguntar si, al crear solo un enum, los estados pueden cambiar arbitrariamente.
Buena pregunta. Por eso concentro las reglas de transición en una sola función.
mutating func fetch() {
guard case .idle = self else { return } // idleIniciar solo cuando esté idle
self = .loading
}
guard caseestablece que «solo se debe pasar a loading cuando el estado actual sea idle».
Al centralizar las condiciones de transición, los estados fluyen solo por rutas definidas, como un semáforo.
Así, incluso al volver a revisar el código, puedes ver de un vistazo desde qué estado puede avanzar cada uno.
P. ¿Qué pasa si hay más de cinco estados?
Enum sigue funcionando bien. Pero cuando las reglas se complican, recomiendo dividir la función de transición en funciones más pequeñas por estado.
P. ¿Funciona bien con SwiftUI?
Muy bien. Si mantienes el estado del enum en @State o @Published y renderizas la vista con switch, el estado y la pantalla avanzan sincronizados.
Al principio unos pocos Bool pueden parecer suficientes, pero cuando los estados empiezan a entrelazarse, acabas volviendo a una FSM con enum.
Si la gestión del estado de la pantalla te da problemas, prueba a sustituirla primero por el enum de hoy. Te resultará más fácil antes de lo que imaginas.

