MVC (Model-View-Controller) é um padrão arquitetural que divide uma aplicação em três componentes: Model é responsável pelos dados e lógica de negócio, View é responsável pela interface do usuário, Controller é responsável pelo processamento de entrada e coordenação entre Model e View. Em iOS, MVC é implementado através de UIViewController, em Android — através de Activity e Fragment. MVC continua sendo o padrão fundamental sobre o qual MVVM, MVP e Clean Architecture são construídos. Saiba mais em MVC in Cocoa Core.
Principais pontos
MVC (Model-View-Controller) é um padrão arquitetural proposto por Trygve Reenskaug em 1979 para a linguagem Smalltalk-80. O padrão divide uma aplicação em três camadas: Model contém dados e lógica de negócio, View é responsável pela exibição, Controller processa a entrada do usuário e atualiza Model e View. A separação de responsabilidades permite alterar cada camada independentemente — por exemplo, substituir View de UIKit para SwiftUI sem alterar a lógica de negócio em Model.
Interação de componentes em MVC segue um ciclo: o usuário interage com View → Controller recebe o evento → Controller atualiza Model → Model notifica Controller sobre mudanças → Controller atualiza View. Na implementação clássica, Model usa o padrão Observer: quando os dados mudam, Model envia notificações, Controller se inscreve e atualiza View. Na implementação da Apple, Key-Value Observing (KVO) ou NotificationCenter desempenham esse papel.
| Componente | Responsabilidade | Exemplo em iOS | Exemplo em Android |
|---|---|---|---|
| Model | Dados, lógica de negócio, rede | Struct User, CoreData | Data class, Repository |
| View | Exibição de UI | Storyboard, XIB, UIView | XML layout, Jetpack Compose |
| Controller | Processamento de entrada, coordenação | UIViewController | Activity, Fragment |
MVC no desenvolvimento móvel moderno é usado menos do que há 10 anos, mas continua essencial para entender. A Apple recomenda MVC para telas simples em aplicações UIKit. O Google não recomenda MVC puro para Android — a documentação oficial sugere MVVM com Jetpack. No entanto, o conhecimento de MVC é necessário para trabalhar com projetos legados e para entender a evolução dos padrões arquiteturais.
Apple MVC é uma implementação personalizada do padrão incorporada no UIKit. UIViewController atua como Controller: gerencia o ciclo de vida da tela (viewDidLoad, viewWillAppear, viewDidDisappear), lida com toques e ações do usuário, atualiza View através de IBOutlets. View é criada no Interface Builder (storyboard ou XIB) ou programaticamente. Model — qualquer objeto de dados: serviços de rede, pilhas CoreData, estruturas Swift.
final class UserViewController: UIViewController {
// View (através de storyboard outlet)
@IBOutlet private var nameLabel: UILabel!
@IBOutlet private var emailLabel: UILabel!
// Model
private let userService = UserService()
override func viewDidLoad() {
super.viewDidLoad()
loadUser()
}
private func loadUser() {
userService.fetchUser { [weak self] user in
// Controller atualiza View
self?.nameLabel.text = user.name
self?.emailLabel.text = user.email
}
}
}
O problema do Apple MVC — View e Controller são fortemente acoplados. UIViewController gerencia simultaneamente View e lógica. Storyboard armazena View em XML, mas o controlador tem referências diretas a elementos UI através de IBOutlets. Isso viola o princípio de responsabilidade única: o controlador é responsável pelo ciclo de vida, delegados, datasource, target-action e animações. Como resultado, uma tela padrão de aplicativo iOS contém 200–500 linhas no controlador.
Ciclo de vida do ViewController — a Apple fornece 6 métodos de ciclo de vida: loadView (criação manual de View), viewDidLoad (após carregar View na memória), viewWillAppear (antes de aparecer na tela), viewDidAppear (após a animação), viewWillDisappear (antes de sair da tela), viewDidDisappear (após sair). Cada método é um lugar para colocar lógica em MVC. Usar esses métodos para lógica de negócio acelera o crescimento do controlador.
Android MVC — Activity e Fragment atuam como Controller, arquivos XML layout como View, qualquer classe POJO com dados como Model. Activity gerencia o ciclo de vida da tela: onCreate, onStart, onResume, onPause, onStop, onDestroy. Fragment é uma subtela dentro de Activity com seu próprio ciclo de vida. View (XML) é separada do Controller e carregada via setContentView ou LayoutInflater. Model — repositórios, bancos de dados, chamadas de rede.
class UserActivity : AppCompatActivity() {
// View através de XML layout
private lateinit var binding: ActivityUserBinding
// Model
private val userRepository = UserRepository()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityUserBinding.inflate(layoutInflater)
setContentView(binding.root)
loadUser()
}
private fun loadUser() {
userRepository.getUser { user ->
runOnUiThread {
binding.nameText.text = user.name
binding.emailText.text = user.email
}
}
}
}
Android ViewBinding e DataBinding — ferramentas modernas que reduzem o acoplamento entre Controller e View. ViewBinding gera uma classe com referências diretas a Views do XML, eliminando findViewById. DataBinding adiciona a capacidade de vincular dados à UI na marcação XML através de @{user.name}. DataBinding é um passo em direção ao MVVM, pois permite passar dados de Model para View sem código em Activity. O Google recomenda DataBinding para todos os novos projetos.
Ciclo de vida do Android é mais complexo que iOS: Activity pode ser destruída e recriada na rotação da tela, falta de memória ou mudança de configuração. Em MVC puro, o controlador (Activity) contém lógica que é perdida na destruição. Isso requer salvar estado através de onSaveInstanceState ou ViewModel do Jetpack, o que vai além do MVC puro e aproxima a arquitetura do MVVM.
Massive View Controller é um termo que descreve o principal problema do MVC no desenvolvimento móvel. O controlador em iOS e Android assume muitas responsabilidades: processamento de entrada, validação de dados, interação de rede, navegação, cache, animações, gerenciamento de ciclo de vida. Como resultado, o controlador cresce para 500–2000 linhas de código, tornando-se difícil de ler, testar e manter.
Causas do Massive View Controller — a arquitetura do UIKit e Android Framework incentiva colocar lógica no controlador. Chamadas de rede, processamento JSON, navegação — tudo isso naturalmente vai para Activity ou UIViewController porque eles têm acesso ao ciclo de vida e à UI. O desenvolvedor deve conscientemente extrair a lógica para classes separadas (Service, Manager, Interactor), o que requer disciplina e compreensão dos princípios arquiteturais.
| Problema do MVC | Descrição | Solução |
|---|---|---|
| Alto acoplamento | Controller conhece View e Model | MVVM — ViewModel não conhece View |
| Complexidade de teste | Controller depende de UIKit/Android | Extrair lógica para serviços |
| Ciclo de vida | Estado é perdido na rotação | ViewModel do Jetpack/SwiftUI |
| Falta de navegação | Controller gerencia transições | Padrão Coordinator, Router |
Testando MVC — Model é testado isoladamente com testes unitários. Controller é difícil de testar devido à dependência de UIKit/UIFoundation. XCTest não permite criar UIViewController sem uma janela de visualização. Para Android, ActivityTestRule e Robolectric resolvem parcialmente o problema, mas os testes são lentos. View geralmente não é testada com testes unitários — para UI são usados testes de captura de tela e testes de UI (XCUITest, Espresso).
Quando MVC é justificado — telas simples com um ou dois elementos (tela de login, perfil, configurações). Protótipos e MVP para validação de hipóteses — MVC é mais rápido de escrever sem camadas adicionais. Projetos com base de código pequena de até 10–15 telas. Em projetos complexos, MVC leva ao acúmulo de dívida técnica e requer refatoração a cada 6–12 meses.
MVC vs MVVM — a principal diferença: em MVVM, o controlador é substituído por ViewModel que não tem referência a View. Os dados são passados através de Observable (SwiftUI), LiveData/StateFlow (Android) ou Combine/RxSwift. ViewModel é testável com testes unitários sem dependências de UI. A Apple recomenda MVVM com SwiftUI desde 2019, o Google — MVVM com LiveData/Flow como arquitetura oficial do Android. MVVM requer mais código para vinculação, mas melhora significativamente a testabilidade.
MVC vs MVP — em MVP (Model-View-Presenter), Presenter é uma camada testável que recebe View através de uma interface. Ao contrário do MVC onde Controller gerencia diretamente View através do UIKit, Presenter não depende do framework — ele funciona através da abstração ViewInterface. MVP foi popular no desenvolvimento Android antes do Jetpack e é usado em projetos legados. Presenter sobrevive a Activity e preserva o estado na rotação da tela.
MVC vs Clean Architecture — Clean Architecture adiciona camadas: Use Cases (Interactors), Entities, Gateways e Repository. MVC permanece na camada de Presentation, mas a lógica de negócio é movida para a camada de Domain com Use Cases. Clean Architecture resolve radicalmente o problema do Massive View Controller — Controller contém apenas chamadas de Use Cases e atualizações de View. A desvantagem é um aumento significativo no número de classes e arquivos, o que é justificado para projetos com 50+ telas.
// MVC em iOS: Controller contém tudo
class OrderViewController: UIViewController {
func placeOrder() {
// Validação + rede + atualização de UI
guard Validation.isValid(total) else { return }
NetworkService.shared.submit(order) { [weak self] result in
self?.handleResult(result)
}
}
}
// MVVM: lógica em ViewModel
class OrderViewModel: ObservableObject {
@Published var state: OrderState = .idle
func placeOrder() { /* lógica de negócio */ }
}
Escolha da arquitetura depende do tamanho da equipe, escopo do projeto e testabilidade necessária. Para uma equipe de 1–2 desenvolvedores e um projeto de até 20 telas, MVVM funciona bem. Para uma equipe grande de 5+ desenvolvedores e um projeto com 50+ telas — Clean Architecture com estrutura modular. MVC continua relevante para entender a evolução das arquiteturas, manter projetos legados e para telas simples de UIKit sem lógica de negócio complexa.
Perguntas frequentes
O principal problema é o Massive View Controller. Em iOS, UIViewController lida com tudo: processamento de entrada, atualização de View, rede, navegação e ciclo de vida. Em Android, Activity/Fragment realiza funções similares. Como resultado, o controlador cresce para milhares de linhas de código, tornando-se difícil de testar e manter, violando o princípio de responsabilidade única.
Em MVC, o controlador atualiza diretamente View e processa a entrada do usuário. Em MVVM, o papel de controlador é desempenhado por ViewModel, que não tem referência a View — os dados são passados através de mecanismos de vinculação. MVVM é mais fácil de testar porque ViewModel não depende de UIKit ou Android Framework. A Apple recomenda MVVM com SwiftUI, o Google recomenda MVVM com Jetpack Compose.
Sim, MVC continua sendo um padrão funcional para telas simples e protótipos. A Apple recomenda MVC para aplicações UIKit com telas simples. Para projetos complexos com muitas telas, requisições de rede e cache, é melhor escolher MVVM, VIPER ou Clean Architecture. Desenvolvedores iniciantes são recomendados a dominar MVC antes de aprender padrões mais complexos.
Model é testado isoladamente — são objetos de dados e lógica de negócio comuns. Controller é difícil de testar devido à dependência de UIKit ou Android Framework. Recomenda-se extrair a lógica de negócio do controlador para serviços ou interactors separados, que são testados com testes unitários. View geralmente não é testada com testes unitários — são usados testes de UI e testes de captura de tela.
Em iOS — MVVM com SwiftUI e Combine, padrão da Apple desde 2019. Em Android — MVVM com LiveData ou StateFlow, oficialmente recomendado pelo Google. Para projetos grandes com equipes de 5+ desenvolvedores — Clean Architecture com VIPER em iOS ou Clean Architecture em Android com separação de módulos por funcionalidade. Para projetos legados com MVC — refatoração gradual com extração de lógica para serviços separados.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também