Introdução
Ultimamente, tenho visto muita gente em fóruns e comunidades iOS com dificuldade pra entender MVVM na prática. Posso dizer por experiência própria que isso é bem comum, pois tive uma falha gigante nesse quesito também. Mas, com ajuda desse artigo, vamos esclarecer como funciona essa arquitetura através de um projeto de descobrir o signo de acordo com a data de aniversário.
Desenvolvimento
Sobre o projeto: Vamos desenvolver um projeto simples que consiga explicar bem as regras e boas práticas do MVVM. Um app onde o usuário digita a data de nascimento e, ao clicar no botão, descobre o signo.
Sobre a arquitetura: Na prática, MVVM consiste apenas em dividir responsabilidades do projeto para cada arquivo, basicamente uma versão "bombada" do MVC.
Se divide em:
Model: camada responsável por conter a estrutura de dados da aplicação, como por exemplo strucks, enums e etc.
View: camada responsável apenas pela interface que o usuário ver na tela do seu iPhone, não contendo regras de negócios.
ViewModel: camada responsável por toda lógica de negócio da aplicação, não acessando a view, e utilizando os dados presentes na Model.
Esta imagem representa o fluxo de uma MVVM padrão:
View mostra ao usuário um botão, por exemplo.
A controller acessa esse botão, e chama a viewModel > "Ei, o usuário clicou no botão, o que eu faço?"
A viewModel faz toda manipulação com as regras de negócio, usando a Model, e devolve para a controller que irá mostrar ao usuário o resultado final da sua ação.
Agora vamos para a prática. E por questão de acelerar o processo, vou mostrar os screenshots das telas e explicar a funcionalidade através de comentários no código e falar sobre como foi aplicado a teoria do MVVM.
Antes de tudo, vale dizer que usei ViewCode em vez do AutoLayout do Storyboard, pois sinto que tenho mais controle para montar telas e dividir responsabilidades. As configurações para implantar o ViewCode não estarão disponíveis nesse artigo, porém é de fácil acesso em outros materiais e fóruns.
Vamos começar com a divisão de pastas e criação de arquivos. Como é um projeto mais simples, sei exatamente quais arquivos vamos precisar.
Antes de começar a codar, criamos uma pasta para cada camada: Contoller, View, ViewModel e Model. Outras pastas como Suport e Resource é mais para organização do projeto.
Agora vamos definir o fluxo da nossa aplicação:
O usuário coloca sua data no campo de texto e ao clicar no botão, mostra uma label com o resultado.
Interface com botões e textos: View
Lógica de quando o user clicar no botão: ViewModel
Enum com cada caso de uso para cada mês: Model
Atualizar a view com o resultado da ViewModel: Controller
View: Interface do projeto
Eu sei que talvez não tenha caprichado tanto no layout, mas ele mostra bem o que precisamos, então está ótimo. haha
Na View temos um título, uma label e um textfield dentro de uma Stack View, uma label que só aparece com o resultado, e por fim, um botão.
O código está comentado para te ajudar a entender o que cada parte é responsável. Mas o que é mais importante: Na View apenas tratamos da interface do projeto, botões, labels e etc. Nada de regras de negócio por aqui.
Uma preferência minha é utilizar delegante para fazer a comunicação do botão com a controller, porém tem outros métodos para fazer isso.
Controller: Ponte entre View e ViewModel
A controller realmente deve ser apenas uma ponte, nada de regras de negócios ou UI da aplicação. Pega o que a view oferece, recebe o resultado da viewModel e mostra ao usuário.
ViewModel: Regra de negócio
A viewModel acaba sendo onde o código vai ser mais trabalhado, pois vamos lidar com toda a lógica. Mas tem uma regra: Não podemos acessar a view, pois deve lidar apenas com as regras. Tenho um macete para isso, se o código pedir import de UIKit, você está fugindo da responsabilidade da ViewModel.
var onSignText: ((String) -> Void)?
var onErrorText: ((String) -> Void)?
var onButtonEnabled: ((Bool) -> Void)?
Atenção para essas linhas, pois serve de comunicador com a controller, como usamos aqui:
func bindViewModel() {
viewModel.onSignText = { [weak self] text in
self?.screen.resultLabel.text = text
self?.screen.resultLabel.textColor = .brown
}
viewModel.onErrorText = { [weak self] text in
self?.screen.resultLabel.text = text
self?.screen.resultLabel.textColor = .systemRed
}
}
Model: Estrutura de dados
A Model é onde fica toda estrutura de dados do projeto, e nesse caso, todos os cases de uso para encontrar o signo baseado na data de aniversário.
Conclusão
O MVVM é basicamente isso, cada camada com sua responsabilidade. Lógico que em aplicativo menores você pode optar por usar outra arquitetura, como MVC, e em projetos maiores, algo como VIPER.
Não é difícil a compreensão desses conceitos, desde que você entenda a lógica de divisão de responsabilidade, e a partir daí, é só replicar para cada tela da aplicação.
Acredito que esse artigo pode te ajudar a entender melhor essa arquitetura, pois eu também sofri com esse obstáculo, e acabava por sempre optar por arquiteturas mais fáceis.
Curtiu? Se tiver dúvidas ou quiser trocar ideia, é só me chamar no Instagram - https://www.instagram.com/davy.developer/ — tamo junto nessa jornada iOS! 🚀
Top comments (0)