Al desarrollar para iOS, casi todos escuchamos alguna vez este chiste.
“MVC no significa Model-View-Controller, sino Massive View Controller.”
Es una broma, pero tiene algo de verdad. Apple recomienda oficialmente esta arquitectura; entonces, ¿por qué seguirla convierte los view controllers en monstruos de miles de líneas?
En esta primera entrega de la serie sobre arquitectura iOS, veremos cómo era originalmente MVC y por qué iOS no puede seguir ese modelo.
En resumen, el problema no es MVC, sino la estructura de UIViewController, que se sitúa entre View y Controller.
¿Cómo era originalmente MVC?
MVC es un patrón muy antiguo, originado en Smalltalk en 1979. En su forma original, sus tres responsabilidades están claramente separadas.
- Model: Datos y lógica de negocio
- View: Presentación de la pantalla
- Controller: Recibe la entrada del usuario y la transmite al Model
En el MVC original, View observa directamente a Model. Cuando Model cambia, View se actualiza automáticamente.
El MVC de Apple es algo distinto. Hace que View y Model no se conozcan y que Controller actúe en el centro como intermediario de todo. Fue una decisión razonable para mejorar la reutilización, pero también dejó abierta la puerta a sobrecargar Controller.
UIViewController hace trampa desde el nombre
En el MVC de Apple, Controller se implementa como UIViewController en iOS. Pero volvamos a mirar el nombre de la clase: View + Controller. El propio nombre combina dos responsabilidades.
En la práctica, UIViewController se encarga de todo esto.
- Gestionar
viewDidLoad,viewWillAppearcomo el ciclo de vida de la vista - Procesar eventos estrechamente ligados a la vista, como la rotación y la actualización del layout
- Implementar
UITableViewDataSource,UITableViewDelegatecomo protocolos de la vista
Hasta aquí siguen siendo tareas relacionadas con la vista. El problema es que no hay una respuesta clara para preguntas como “¿Dónde escribo las solicitudes de red?”, “¿Y la navegación?”, o “¿El formateo de datos?”. Como no pertenecen a Model ni a View, todo acaba en el view controller.
La forma típica de un view controller sobredimensionado
Esta es una síntesis en código de la estructura habitual de un view controller.
final class ProfileViewController: UIViewController {
// 1. Propiedades de la vista
private let tableView = UITableView()
// 2. Estado (en la práctica, una Model caché)
private var user: User?
private var posts: [Post] = []
override func viewDidLoad() {
super.viewDidLoad()
setupLayout() // 3. Código de layout
fetchProfile() // 4. Solicitudes de red
}
private func fetchProfile() {
URLSession.shared.dataTask(...) { ... } // 5. Parsing y gestión de errores
}
@objc private func editTapped() {
// 6. Incluso la navegación directamente
navigationController?.pushViewController(EditViewController(), animated: true)
}
}
El layout, la gestión del estado, la red, el parsing y la navegación están en un solo archivo. Si además se implementan delegates, pronto supera las mil líneas.
El coste real de esta estructura no es el número de líneas, sino que las pruebas se vuelven imposibles. Incluso para verificar una lógica simple como “el botón Editar se oculta si user es nil”, hay que iniciar UIViewController completo y simular su ciclo de vida.
Entonces, ¿debemos abandonar MVC?
No necesariamente. En pantallas pequeñas, MVC sigue siendo la opción más rápida y sencilla. Los frameworks de Apple están diseñados sobre MVC, así que imponer otra estructura puede generar más fricción.
La clave es extraer conscientemente las responsabilidades que puedan salir del view controller, incluso al usar MVC.
- Lógica de red y datos → Objetos de servicio independientes
- Navegación → Objetos dedicados como Coordinator
- Configuración de celdas y formateo → Tipos específicos
Llega un momento en que también quieres separar la lógica que crea “el estado que se mostrará en pantalla”. La respuesta es MVVM, que veremos en la próxima entrega. También explicaremos por qué hace falta un ViewModel y por qué sin binding solo está completo a medias.
Resumen
- MVC no tiene la culpa. El problema es la característica estructural de iOS: UIViewController cumple a la vez los roles de View y Controller.
- El código que no es Model ni View no tiene dónde ir y se acumula en el view controller. Esa es la verdadera naturaleza del Massive View Controller.
- MVC sigue siendo válido para pantallas pequeñas. Sin embargo, la red, la navegación y el formateo deben separarse de forma consciente.
- Para separar también la lógica que crea el estado de la vista, hace falta MVVM. Lo veremos en la próxima entrega.

![Imagen de portada de [Arquitectura iOS #1] MVC en iOS y la verdadera razón de los Massive View Controllers](/assets/images/posts/a3101292-21b1-4a89-b770-3e844f1a23c6/1.jpg)