Engenharia iOS

Padrão Coordinator no iOS: separe a navegação do controller

Ao criar apps iOS, chega um momento em que o view controller fica inchado.

4 min de leitura
Imagem de capa de Padrão Coordinator no iOS: separe a navegação do controller

Ao criar apps iOS, chega um momento em que o view controller fica inchado.

O código de UI, o processamento de dados e até pushViewController a navegação acabam misturados.

Se você deixar assim, quanto mais complexo o fluxo, mais difícil fica rastrear cada transição.

Hoje vamos falar sobre o padrão Coordinator do iOS, que separa a navegação do view controller.

Em resumo, o padrão Coordinator adiciona um objeto separado responsável pela navegação. O view controller desenha a tela e deixa o Coordinator decidir para onde ir em seguida.


O que é o padrão Coordinator?

Em uma linha:

Coordinator é um objeto dedicado ao fluxo de navegação entre telas.

Antes, o view controller desenhava a tela, recebia a entrada do usuário e também apresentava a próxima tela.

Dessa tarefa, extraímos a transição para a próxima tela e a delegamos ao Coordinator.

Assim, o view controller só precisa informar ao Coordinator que um botão foi pressionado.

Ele não precisa saber para onde nem como a transição acontecerá.

Os view controllers deixam de conhecer uns aos outros diretamente. A tela A não precisa conhecer a B, o que facilita muito a reutilização.


Por que separar a navegação?

Manter código de navegação dentro do view controller causa vários problemas.

Reuni aqui os que vivi na prática.

  • Dependências entrelaçadas: A cria B diretamente; se B mudar, A também precisa ser alterada.
  • Sem reutilização: para usar a mesma tela em outro fluxo, é preciso alterar a navegação novamente.
  • Fluxo difícil de entender: a lógica de navegação se espalha por 20 arquivos e a visão geral desaparece.
  • Testes difíceis: a navegação fica presa ao view controller, dificultando testes isolados.

Centralizar a navegação resolve boa parte desses problemas.

Basta olhar um arquivo de Coordinator para entender o fluxo de telas do app.


Como criar um Coordinator?

A estrutura básica é mais simples do que parece.

Primeiro, defina um protocolo comum. start() funciona como ponto de entrada.

protocol Coordinator: AnyObject {
    var navigationController: UINavigationController { get }
    func start()
}

Depois, crie o Coordinator real, responsável por criar e apresentar a primeira tela.

final class MainCoordinator: Coordinator {
    let navigationController: UINavigationController
    init(nav: UINavigationController) { self.navigationController = nav }

    func start() {
        let vc = HomeViewController()
        vc.coordinator = self          // canal para receber solicitações de navegação
        navigationController.pushViewController(vc, animated: false)
    }

    func showDetail() {                // a navegação para a próxima tela acontece somente aqui
        let vc = DetailViewController()
        navigationController.pushViewController(vc, animated: true)
    }
}

Quando o botão é pressionado, o view controller só precisa chamar coordinator?.showDetail().

Um toque no botão, e o Coordinator cuida do resto
Um toque no botão, e o Coordinator cuida do resto

Você não precisa se preocupar com o destino nem com a forma de inserir a tela.

Deixando apenas esta chamada, o view controller fica muito mais leve
Deixando apenas esta chamada, o view controller fica muito mais leve

Qual é a diferença para fazer push ou usar Segue diretamente?

É uma dúvida comum, então organizei tudo em uma tabela.

Item Push direto / Segue Padrão Coordinator
Local da navegação Dentro do view controller Centralizada no Coordinator
Dependência entre telas Conhecem-se diretamente Não precisam se conhecer
Reutilização de telas Difícil Fácil
Entendimento do fluxo Espalhado por vários arquivos Gerenciado em um só lugar
Trabalho inicial Menor Um pouco maior

Como você pode ver, Coordinator não resolve tudo.

Em um app pequeno com apenas duas ou três telas, ele pode aumentar o código e acabar complicando mais do que ajudando.

Por outro lado, em apps com fluxos ramificados, como login, onboarding ou troca de abas, ele realmente vale a pena.

Quanto mais caminhos o fluxo tiver, mais útil ele será
Quanto mais caminhos o fluxo tiver, mais útil ele será

Perguntas frequentes

P. Se há várias telas, devo criar vários Coordinators?

Sim. Normalmente, eles são divididos por fluxo: login, fluxo principal e assim por diante. É comum um Coordinator superior gerenciar os inferiores como filhos.

P. Quando devo remover um Coordinator filho?

Quando o fluxo termina, o pai precisa remover a referência ao filho do array. Caso contrário, ele continua na memória e causa um vazamento.

P. Também é usado com SwiftUI?

O SwiftUI tem roteamento baseado em NavigationStack e path, então a abordagem é um pouco diferente. Ainda assim, a ideia de extrair o fluxo para um objeto separado pode ser aplicada da mesma forma.


No início, adicionar mais um arquivo pode parecer trabalhoso.

Mas, quando o app crescer para dez ou vinte telas, você vai perceber o valor dessa estrutura.

Comece extraindo um fluxo pequeno para um Coordinator. Você sentirá o view controller ficar bem mais leve. 🙂

Artigos recomendados