Ao desenvolver para iOS, quase todo mundo ouve esta piada pelo menos uma vez.
“MVC não significa Model-View-Controller, mas Massive View Controller.”
É uma piada, mas contém uma verdade. A Apple recomenda oficialmente essa arquitetura; então por que segui-la transforma os view controllers em monstros de milhares de linhas?
Nesta primeira parte da série sobre arquitetura iOS, vamos revisar como era o MVC originalmente e por que o iOS não segue esse modelo.
Em resumo, o problema não é o MVC, mas a estrutura do UIViewController, que fica entre View e Controller.
Como era o MVC originalmente?
MVC é um padrão muito antigo, criado no Smalltalk em 1979. Na forma original, suas três responsabilidades eram claramente separadas.
- Model: Dados e lógica de negócio
- View: Exibição da tela
- Controller: Recebe a entrada do usuário e a encaminha ao Model
No MVC original, a View observa o Model diretamente. Quando o Model muda, a View é atualizada automaticamente.
O MVC da Apple é um pouco diferente. View e Model não conhecem um ao outro, e o Controller fica no meio, fazendo toda a mediação. Foi uma escolha razoável para aumentar a reutilização, mas também abriu espaço para sobrecarregar o Controller.
UIViewController já quebra as regras pelo próprio nome
No MVC da Apple, o Controller é implementado como UIViewController no iOS. Mas veja novamente o nome da classe: View + Controller. O próprio nome combina duas responsabilidades.
Na prática, UIViewController cuida de tudo isso.
- Gerenciamento de
viewDidLoad,viewWillAppearcomo o ciclo de vida da view - Processamento de eventos ligados à view, como rotação de tela e atualização de layout
- Implementação de
UITableViewDataSource,UITableViewDelegatecomo protocolos da view
Até aqui, ainda são tarefas relacionadas à view. O problema é não haver uma resposta clara para perguntas como “Onde escrevo as requisições de rede?”, “E a navegação?”, ou “A formatação de dados?”. Como não são Model nem View, tudo acaba no view controller.
A aparência típica de um view controller inchado
A estrutura comum de um view controller pode ser resumida em código assim.
final class ProfileViewController: UIViewController {
// 1. Propriedades da view
private let tableView = UITableView()
// 2. Estado (na prática, um Model cache)
private var user: User?
private var posts: [Post] = []
override func viewDidLoad() {
super.viewDidLoad()
setupLayout() // 3. Código de layout
fetchProfile() // 4. Requisições de rede
}
private func fetchProfile() {
URLSession.shared.dataTask(...) { ... } // 5. Parsing e tratamento de erros
}
@objc private func editTapped() {
// 6. Até a navegação diretamente
navigationController?.pushViewController(EditViewController(), animated: true)
}
}
Layout, gerenciamento de estado, rede, parsing e navegação ficam todos no mesmo arquivo. Quando você adiciona implementações de delegate, ele passa rapidamente de mil linhas.
O custo real dessa estrutura não é o número de linhas, mas o fato de que os testes se tornam impossíveis. Até para verificar uma lógica simples como “o botão Editar fica oculto quando user é nil”, é preciso iniciar o UIViewController inteiro e simular seu ciclo de vida.
Então devemos abandonar o MVC?
Não necessariamente. Para telas pequenas, MVC ainda é a opção mais rápida e simples. Os frameworks da Apple foram projetados com MVC como base, então forçar outra estrutura pode gerar mais atrito.
O ponto central é, mesmo usando MVC, separar conscientemente as responsabilidades que podem sair do view controller.
- Lógica de rede e dados → Objetos de serviço separados
- Navegação → Objetos dedicados, como Coordinator
- Configuração de células e formatação → Tipos específicos
Em algum momento, você também vai querer separar a lógica que cria “o estado a ser exibido na tela”. A resposta é MVVM, tema da próxima parte. Vamos explicar por que um ViewModel é necessário e por que, sem binding, ele fica incompleto.
Resumo
- O MVC não tem culpa. O problema é a característica estrutural do iOS: UIViewController desempenha os papéis de View e Controller ao mesmo tempo.
- O código que não é Model nem View fica sem destino e se acumula no view controller. Essa é a verdadeira identidade do Massive View Controller.
- MVC continua válido para telas pequenas. Porém, rede, navegação e formatação devem ser separadas conscientemente.
- Para separar também a lógica que cria o estado da view, é preciso usar MVVM. Veremos isso na próxima parte.

![Imagem de capa de [Arquitetura iOS #1] MVC no iOS e o verdadeiro motivo dos Massive View Controllers](/assets/images/posts/a3101292-21b1-4a89-b770-3e844f1a23c6/1.jpg)