路由器和数据传递Clean Swift体系结构

读者好!

一篇文章中,我谈到了Clean Swift架构的VIP周期。 现在,我们将讨论最重要的主题之一-场景之间的数据 转换传输



理论


路由器组件负责导航和数据传输逻辑,这是场景的一部分(当然是可选的)。 它在ViewController中InteractorPresenter一起初始化。

路由器实现了两个协议-RoutingLogicDataPassing ,我们将在其中填充我们的功能。 RoutingLogic应该包含负责过渡到特定场景的方法。 DataPassing包含变量dataStore ,该变量引用协议DataStoreInteractor Scenes实现了DataStore协议并使用其中存储的变量。 路由器本身包含一个指向其场景的ViewController的链接。

使用到ViewController的链接, 路由器在场景之间跳转。 为此,您可以使用Segue或以编程方式创建要向其过渡的场景。 使用哪种方法并不重要,对我们来说,最主要的是要链接到我们要切换到的ViewController类的实例。

使用到数据存储的链接我们将数据从一个场景的交互器传输到我们要切换到场景的交互器 。 而且,如前所述, 路由器需要知道如何执行此操作。

练习


例如,我们将文本从TextField传输到其他场景的Label。 让我们考虑两种场景之间的过渡方式-根据Segue和以编程方式。

Router类包含3个方法的语义组:

  1. RoutingLogic实现中的方法(routeTo)
  2. 负责导航的方法(navigateTo,不带Segue的过渡)
  3. 数据传输方法(passDataTo,如果有要传输的数据)



例如,如果我们通过Segue进行过渡,则当单击按钮时,则在ViewController中,我们必须重写prepare(for:sender :)方法。 该扩展名将允许您使用Segue的名称自动从Router调用方法。

在使用Segue时,可选的prepare(对于:sender :)是可选的。 您可以将其从代码中排除,然后在Router方法中调用performSegue(withIdentifier:sender :) 仅当您需要在数据传输中使用Segue时才需要进行准备

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)
}
}
}
// ...
}


现在,我们终于找到了最有趣的东西- 路由器代码。 该示例包含注释,因此我们将仅考虑关键点。

在此路由器中,我们处理两个场景-HomeDetail 。 从Home场景的过渡也有两种处理方式-Segue编程方式 。 数据从Home场景传输到Detail场景。

必须根据routeToNAME原则来命名RoutingLogic协议中的所有方法,其中NAME是我们在使用Storyboard时指定的Segue (标识符)的名称。 这不仅是为了方便使用和美观,而且对于我们在前面重新定义的prepare(for:sender :) ViewController中的方法选择器也是必需的。

同样,在HomeRouter类中, 还有一些方法以NavigationTopassDataTo开头 。 前者负责转换逻辑,而后者负责数据传输。 仅当以编程方式完成过渡时才创建navigationTo方法。

在示例中,我们有一个routeToDetail(segue :)方法。 segue参数可选的,因为 该方法包含一个实现,使您无需使用Segue即可调用它。 在两种过渡情况下,我们都将获得HomeViewController'aHomeDataStore'a Home场景的非可选值,以及指向ViewControllerDataStore Detail场景的链接。 这里值得注意的事实是, detailDS是一个变量,并使用pass- through参数(inout)传递给passDataToDetail方法。 这很重要,因为 没有inout,我们将必须将所有DataStore协议标记为“仅可以使用类来实现”(Protocol DetailDataStore:class),这会带来许多困难,包括捕获牢固的链接。

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
}
}


结论


仅此而已。 感谢您阅读到底! 如果您想尝试本文,我将在下面留下该项目的链接。

系列文章


  1. Clean Swift体系结构概述
  2. Clean Swift架构中的路由器和数据传递(您在此处)
  3. 干净迅速的建筑工人
  4. Clean Swift架构中的单元测试
  5. 一个简单的在线商店架构Clean Swift的示例

链接到项目
撰写文章的帮助: Bastien

Source: https://habr.com/ru/post/zh-CN454032/


All Articles