Bonjour lecteur!
Dans un article
précédent , j'ai parlé du cycle
VIP de l'architecture
Clean Swift . Nous allons maintenant aborder l'un des sujets les plus importants - la
transition et le
transfert de données entre les scènes.

Théorie
Le composant
Router est responsable de la logique de navigation et de transfert de données, qui fait partie de la scène (facultatif bien sûr). Il est initialisé dans le
ViewController , avec l'
Interactor et le
Presenter .
Le routeur implémente deux protocoles -
RoutingLogic et
DataPassing , que nous remplirons de nos fonctionnalités.
RoutingLogic doit contenir les méthodes responsables de la transition vers une scène spécifique.
DataPassing contient la variable
dataStore , qui fait référence au Protocol
DataStore .
Interactor Scenes implémente le protocole
DataStore et fonctionne avec les variables qui y sont stockées.
Le routeur lui-même contient un lien vers le
ViewController de sa scène.
En utilisant le lien vers le
ViewController , le
routeur saute entre les scènes. Pour ce faire, vous pouvez utiliser
Segue ou créer une scène vers laquelle vous souhaitez effectuer une transition, par programme. La méthode utilisée n'est pas importante, l'essentiel pour nous est d'avoir un lien vers une instance de la classe
ViewController vers laquelle nous
basculons .
En utilisant le lien vers le
DataStore, nous transférerons les données de l'
interacteur d' une scène vers l'
interacteur de la scène vers laquelle nous basculons. Et, comme mentionné précédemment, c'est le
routeur qui doit savoir comment procéder.
Pratique
Par exemple, nous allons transférer le texte de TextField vers Label d'une autre scène. Considérons deux façons de transition entre les scènes - selon
Segue et par programme.
La classe
Router contient 3 groupes sémantiques de méthodes:
- Méthodes de l' implémentation de RoutingLogic (routeTo)
- Méthodes responsables de la navigation (naviguer vers, transition sans Segue)
- Méthodes de transfert de données (passDataTo, s'il existe des données à transférer)

Si nous effectuons une transition via
Segue , par exemple, lorsqu'un bouton est cliqué, alors dans
ViewController, nous devons remplacer la méthode prepare (for: sender :). Cette extension vous permettra d'appeler automatiquement des méthodes depuis le
routeur sous le nom de
Segue .
Remplacer préparer (pour: expéditeur :) est facultatif lorsque vous travaillez avec Segue. Vous pouvez l'exclure du code et appeler performSegue (withIdentifier: sender :) dans la méthode Router . La préparation n'est nécessaire que si vous devez utiliser Segue avec le transfert de données. | 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) |
| } |
| } |
| } |
| |
| // ... |
| } |
Maintenant, nous arrivons enfin à la chose la plus intéressante - le code du
routeur . L'exemple contient des commentaires, nous ne considérerons donc que les points clés.
Dans ce
routeur, nous travaillons avec deux scènes -
Home et
Detail . La transition de la scène d'
accueil est également gérée de deux manières - par
Segue et par
programme . Les données sont transférées de la scène d'
accueil à la scène de
détail .
Toutes les méthodes du protocole
RoutingLogic doivent être nommées selon le principe
routeToNAME , où
NAME est le nom du
Segue (identifiant) que nous spécifions lorsque nous travaillons avec le
Storyboard . Cela est nécessaire non seulement pour la commodité et la beauté de l'utilisation, mais aussi pour notre sélecteur de méthode dans
prepare (pour: sender :) ViewController , que nous avons redéfini plus tôt.
Dans la classe
HomeRouter ,
il existe également des méthodes commençant par
naviguerTo et
passDataTo . Les premiers sont responsables de la logique de transition, tandis que les seconds sont responsables du transfert des données. Les méthodes naviguer vers ne sont créées que si la transition est effectuée par programme.
Dans l'exemple, nous avons une
méthode routeToDetail (segue :) . Le paramètre
segue est facultatif car la méthode contient une implémentation qui vous permet de l'appeler sans utiliser
Segue . Dans les deux cas de transition, nous obtenons des valeurs non facultatives de notre scène
HomeViewController et
HomeDataStore'a Home , ainsi que des liens vers la scène
ViewController et
DataStore Detail . Ici, il convient de prêter attention au fait que
detailDS est une variable et est passée à la méthode
passDataToDetail en utilisant le paramètre
pass -through (inout). Ceci est important car sans
inout, nous devrons marquer tous les protocoles
DataStore comme «possible à implémenter uniquement avec des classes» (protocole DetailDataStore: classe), ce qui entraîne de nombreuses difficultés, notamment la capture de liens forts.
| |
| 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 |
| } |
| } |
Conclusion
C’est tout. Merci d'avoir lu jusqu'au bout! Ci-dessous, je laisserai un lien vers le projet si vous souhaitez essayer l'article en action.
Série d'articles
- Présentation de Clean Swift Architecture
- Routeur et passage de données dans une architecture Clean Swift (vous êtes ici)
- Travailleurs de l'architecture propre et rapide
- Tests unitaires dans l'architecture Clean Swift
- Un exemple d'une architecture de boutique en ligne simple Clean Swift
Lien vers le projetAide à la rédaction d'un article:
Bastien