Hallo Leser!
In einem 
früheren Artikel habe ich über den 
VIP- Zyklus der 
Clean Swift- Architektur gesprochen. Jetzt werden wir eines der wichtigsten Themen ansprechen - den 
Übergang und die 
Übertragung von Daten zwischen Szenen.

Theorie
Die 
Router- Komponente ist für die Navigations- und Datenübertragungslogik verantwortlich, die Teil der Szene ist (natürlich optional). Es wird im 
ViewController zusammen mit dem 
Interactor und dem 
Presenter initialisiert.
Der Router implementiert zwei Protokolle - 
RoutingLogic und 
DataPassing , die wir mit unserer Funktionalität füllen werden. 
RoutingLogic sollte die Methoden enthalten, die für den Übergang zu einer bestimmten Szene verantwortlich sind. 
DataPassing enthält die Variable 
dataStore , die auf den Protocol 
DataStore verweist . 
Interactor Scenes implementiert das 
DataStore- Protokoll und arbeitet mit den darin gespeicherten Variablen. 
Der Router selbst enthält einen Link zum 
ViewController seiner Szene.
Über den Link zum 
ViewController springt der 
Router zwischen den Szenen. Dazu können Sie 
Segue verwenden oder programmgesteuert eine Szene erstellen, zu der Sie einen Übergang vornehmen möchten. Welche Methode verwendet wird, ist nicht wichtig. Für uns ist es wichtig, einen Link zu einer Instanz der 
ViewController- Klasse zu haben, zu der wir wechseln.
Über den Link zum 
DataStore übertragen wir Daten vom 
Interactor einer Szene zum 
Interactor der Szene, zu der wir wechseln. Und wie bereits erwähnt, muss der 
Router wissen, wie das geht.
Übe
Zum Beispiel übertragen wir den Text von TextField auf Label einer anderen Szene. Betrachten wir zwei Arten des Übergangs zwischen Szenen - nach 
Segue und programmgesteuert.
Die 
Router- Klasse enthält 3 semantische Gruppen von Methoden:
- Methoden aus der RoutingLogic- Implementierung (routeTo)
- Navigationsmethoden (navigieren zu, Übergang ohne Segue)
- Methoden zur Datenübertragung (passDataTo, wenn Daten zur Übertragung vorhanden sind)

Wenn wir beispielsweise beim 
Klicken auf eine Schaltfläche einen Übergang durch 
Segue vornehmen , müssen wir in 
ViewController die Methode prepare (for: sender :) überschreiben. Mit dieser Erweiterung können Sie automatisch Methoden vom 
Router mit dem Namen 
Segue aufrufen.
Das Überschreiben der Vorbereitung (für: Absender :) ist optional, wenn Sie mit Segue arbeiten. Sie können es aus dem Code ausschließen und performSegue (withIdentifier: sender :) in der Router- Methode aufrufen . Die Vorbereitung ist nur erforderlich, wenn Sie Segue zusammen mit der Datenübertragung verwenden müssen.|  | 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) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // ... | 
|  | } | 
Jetzt kommen wir endlich zu dem interessantesten - dem 
Router- Code. Das Beispiel enthält Kommentare, daher werden nur wichtige Punkte berücksichtigt.
In diesem 
Router arbeiten wir mit zwei Szenen - 
Home und 
Detail . Der Übergang von der 
Home- Szene erfolgt ebenfalls auf zwei Arten - von 
Segue und 
programmgesteuert . Daten werden von der 
Home- Szene in die 
Detail- Szene übertragen.
Alle Methoden im 
RoutingLogic- Protokoll müssen nach dem 
routeToNAME- Prinzip benannt werden, wobei 
NAME der Name des 
Segues (Bezeichners) ist, den wir bei der Arbeit mit dem 
Storyboard angeben. Dies ist nicht nur für die Benutzerfreundlichkeit und Schönheit der Verwendung erforderlich, sondern auch für unseren Methodenselektor zur 
Vorbereitung (für: Absender :) ViewController , den wir zuvor neu definiert haben.
Auch in der 
HomeRouter- Klasse 
gibt es Methoden, die mit 
navigTo und 
passDataTo beginnen . Die ersteren sind für die Übergangslogik verantwortlich, während die letzteren für die Datenübertragung verantwortlich sind. Die navigateTo-Methoden werden nur erstellt, wenn der Übergang programmgesteuert erfolgt.
Im Beispiel haben wir eine 
routeToDetail (segue :) -Methode. Der Parameter 
segue ist seitdem optional Die Methode enthält eine Implementierung, mit der Sie sie ohne Verwendung von 
Segue aufrufen können. In beiden Übergangsfällen erhalten wir nicht optionale Werte für unsere 
HomeViewController'a- und 
HomeDataStore'a- Home- Szene sowie Links zu 
ViewController- und 
DataStore-Detailszene . Hierbei ist zu beachten, dass 
detailDS eine Variable ist und 
mit dem Parameter 
pass -through (inout) an die Methode passDataToDetail übergeben wird. Das ist wichtig, weil Ohne 
Inout müssen wir alle 
DataStore- Protokolle als "nur mit Klassen implementierbar" (Protokoll DetailDataStore: class) markieren. Dies bringt viele Schwierigkeiten mit sich, einschließlich der Erfassung starker Links.
|  |  | 
|  | 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 | 
|  | } | 
|  | } | 
Fazit
Das ist alles. Vielen Dank für das Lesen bis zum Ende! Unten werde ich einen Link zum Projekt hinterlassen, wenn Sie den Artikel in Aktion ausprobieren möchten.
Artikelserie
- Übersicht über die saubere Swift-Architektur
- Router- und Datenübergabe in Clean Swift-Architektur (Sie sind hier)
- Arbeiter sauberer schneller Architektur
- Unit-Tests in der Clean Swift-Architektur
- Ein Beispiel für eine einfache Online-Shop-Architektur Clean Swift
Link zum ProjektHilfe beim Schreiben eines Artikels: 
Bastien