Olá leitor!
Em um artigo 
anterior , falei sobre o ciclo 
VIP da arquitetura 
Clean Swift . Agora, abordaremos um dos tópicos mais importantes - a 
transição e a 
transferência de dados entre cenas.

Teoria
O componente 
Router é responsável pela lógica de navegação e transferência de dados, que faz parte da cena (opcional, é claro). É inicializado no 
ViewController , junto com o 
Interactor e o 
Presenter .
O roteador implementa dois protocolos - 
RoutingLogic e 
DataPassing , que preencheremos com nossa funcionalidade. 
RoutingLogic deve conter os métodos responsáveis pela transição para uma cena específica. 
DataPassing contém a variável 
dataStore , que se refere ao Protocolo 
DataStore . 
O Interactor Scenes implementa o protocolo 
DataStore e trabalha com as variáveis armazenadas nele. 
O próprio 
roteador contém um link para o 
ViewController de sua cena.
Usando o link para o 
ViewController , o 
roteador salta entre as cenas. Para fazer isso, você pode usar o 
Segue ou criar uma cena para a qual deseja fazer uma transição programaticamente. Qual método usado não é importante, o principal para nós é ter um link para uma instância da classe 
ViewController para a qual estamos mudando.
Usando o link para o 
DataStore, transferiremos dados do 
Interator de uma cena para o 
Interactor da cena para a qual estamos mudando. E, como mencionado anteriormente, é o 
roteador que precisa saber como fazer isso.
Prática
Por exemplo, transferiremos o texto do TextField para o Label de outra cena. Vamos considerar duas maneiras de transição entre cenas - de acordo com 
Segue e programaticamente.
A classe 
Router contém 3 grupos de métodos semânticos:
- Métodos da implementação RoutingLogic (routeTo)
- Métodos responsáveis pela navegação (navigateTo, transição sem Segue)
- Métodos para transferência de dados (passDataTo, se houver dados para transferência)

Se fizermos uma transição pelo 
Segue , por exemplo, quando um botão é clicado, no 
ViewController , devemos substituir o método prepare (for: sender :). Esta extensão permitirá que você chame automaticamente métodos do 
roteador com o nome de 
Segue .
A substituição da preparação (para: remetente :) é opcional ao trabalhar com o Segue. Você pode excluí-lo do código e chamar performSegue (withIdentifier: sender :) no método Router . A preparação é necessária apenas se você precisar usar o Segue junto com a transferência de dados.|  | final class HomeViewController: UIViewController { | 
|  | // ... | 
|  |  | 
|  | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { | 
|  | // Segue | 
|  | if let scene = segue.identifier { | 
|  |  | 
|  | // , Router | 
|  | // router?.routeToNAME(segue:) | 
|  | let selector = NSSelectorFromString("routeTo\(scene)WithSegue:") | 
|  |  | 
|  | // , | 
|  | // Segue | 
|  | if let router = router, router.responds(to: selector) { | 
|  | router.perform(selector, with: segue) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // ... | 
|  | } | 
Agora finalmente chegamos à coisa mais interessante - o código do 
roteador . O exemplo contém comentários, portanto, consideraremos apenas os principais pontos.
Neste 
roteador, trabalhamos com duas cenas - 
Casa e 
Detalhe . A transição da cena 
inicial também é tratada de duas maneiras - por 
Segue e 
programaticamente . Os dados são transferidos da cena 
inicial para a cena 
detalhada .
Todos os métodos no protocolo 
RoutingLogic devem ser nomeados de acordo com o princípio 
routeToNAME , em que 
NAME é o nome do 
Segue (Identificador) que especificamos ao trabalhar com o 
Storyboard . Isso é necessário não apenas para a conveniência e a beleza do uso, mas também para o nosso seletor de métodos em 
prepare (para: remetente :) ViewController , que redefinimos anteriormente.
Também na classe 
HomeRouter, existem métodos que começam com 
navigateTo e 
passDataTo . Os primeiros são responsáveis pela lógica de transição, enquanto os últimos são responsáveis pela transferência de dados. Os métodos navigateTo são criados apenas se a transição for feita programaticamente.
No exemplo, temos um 
método routeToDetail (segue :) . O parâmetro 
segue é opcional, pois o método contém uma implementação que permite chamá-lo sem usar o 
Segue . Nos dois casos de transição, obtemos valores não opcionais da cena 
HomeViewController'a e 
HomeDataStore'a Home , bem como links para a 
cena ViewController e 
DataStore Detail . Aqui vale a pena prestar atenção ao fato de que 
detailDS é uma variável e é passada para o método 
passDataToDetail usando o parâmetro 
pass- through (inout). Isso é importante porque sem o 
inout, teremos de marcar todos os protocolos do 
DataStore como “possíveis de implementar apenas com classes” (protocolo DetailDataStore: class), e isso implica muitas dificuldades, incluindo a captura de links fortes.
|  |  | 
|  | import UIKit | 
|  |  | 
|  | /// @objc | 
|  | /// prepare View Controller'e | 
|  | @objc protocol HomeRoutingLogic { | 
|  | /// Detail View Controller | 
|  | func routeToDetail(segue: UIStoryboardSegue?) | 
|  | } | 
|  |  | 
|  | protocol HomeDataPassing { | 
|  | var dataStore: HomeDataStore? { get } | 
|  | } | 
|  |  | 
|  | final class HomeRouter: NSObject, HomeRoutingLogic, HomeDataPassing { | 
|  |  | 
|  | // MARK: - Private | 
|  |  | 
|  | // MARK: - Public | 
|  |  | 
|  | weak var viewController: HomeViewController? | 
|  | var dataStore: HomeDataStore? | 
|  |  | 
|  | // MARK: - HomeRoutingLogic | 
|  |  | 
|  | func routeToDetail(segue: UIStoryboardSegue?) { | 
|  | if let segue = segue { | 
|  | // | 
|  | // Segue | 
|  |  | 
|  | // Detail View Controller | 
|  | // Data Store Router'e | 
|  | guard | 
|  | let homeDS = dataStore, | 
|  | let detailVC = segue.destination as? DetailViewController, | 
|  | var detailDS = detailVC.router?.dataStore | 
|  | else { fatalError("Fail route to detail") } | 
|  |  | 
|  | // , , , | 
|  | // "" | 
|  | passDataToDetail(source: homeDS, destination: &detailDS) | 
|  | } else { | 
|  | // , | 
|  | // Segue | 
|  |  | 
|  | // Detail View Controller Storyboard'a | 
|  | // Data Store Router'e | 
|  | guard | 
|  | let viewController = viewController, | 
|  | let homeDS = dataStore, | 
|  | let storyboard = viewController.storyboard, | 
|  | let detailVC = storyboard.instantiateViewController(withIdentifier: "Detail") as? DetailViewController, | 
|  | var detailDS = detailVC.router?.dataStore | 
|  | else { fatalError("Fail route to detail") } | 
|  |  | 
|  | passDataToDetail(source: homeDS, destination: &detailDS) | 
|  |  | 
|  | // , "" | 
|  | navigateToDetail(source: viewController, destination: detailVC) | 
|  | } | 
|  | } | 
|  |  | 
|  | // MARK: - Navigation | 
|  |  | 
|  | private func navigateToDetail(source: HomeViewController, destination: DetailViewController) { | 
|  | source.navigationController?.pushViewController(destination, animated: true) | 
|  | } | 
|  |  | 
|  | // MARK: - Passing data | 
|  |  | 
|  | /// destination inout, | 
|  | /// Data Store | 
|  | private func passDataToDetail(source: HomeDataStore, destination: inout DetailDataStore) { | 
|  |  | 
|  | // HomeDataStore DetailDataStore | 
|  | destination.message = source.message | 
|  | } | 
|  | } | 
Conclusão
Só isso. Obrigado por ler até o fim! Abaixo deixarei um link para o projeto, se você quiser experimentar o artigo em ação.
Série de artigos
- Visão geral da arquitetura Clean Swift
- Roteador e transmissão de dados na arquitetura Clean Swift (você está aqui)
- Trabalhadores da arquitetura Clean Swift
- Teste de unidade na arquitetura Clean Swift
- Um exemplo de uma arquitetura simples de loja online Clean Swift
Link para o projetoAjuda para escrever um artigo: 
Bastien