Clean Swift架构:无Segue的路由设计及数据传递实现咨询
在Clean Swift中替代Segue的Router设计方案
当然可以在Clean Swift架构里完全摆脱Segue来做视图控制器的导航和数据传递,而且有几种非常便捷的设计思路,同时完全可以不依赖Segue实现数据传递——这反而更贴合Clean Swift的单向数据流和分层解耦原则。
一、常用的无Segue导航方案
- 直接实例化VC+属性/闭包传参:Router直接创建目标视图控制器的实例,通过属性赋值或者闭包回调传递数据,同时负责执行push/present等导航操作,这是最直观灵活的方式。
- 协议驱动的导航:定义统一的导航协议,让Router遵守该协议,视图控制器只需要调用协议方法即可触发导航,不用关心具体的导航实现细节,进一步解耦VC和Router。
- Presenter触发导航:严格遵循Clean Swift的分层,由Presenter处理业务逻辑后,调用Router的导航方法,Router负责执行具体的页面跳转和数据传递,符合架构的单向依赖原则。
二、最简完整示例
我们实现一个简单场景:从HomeViewController跳转到DetailViewController,传递一个User模型数据,全程不使用Segue。
1. 定义数据模型
struct User { let id: Int let name: String }
2. 实现Router(协议+类)
// 定义导航协议,规范Router的行为 protocol HomeRoutingLogic { func navigateToDetail(with user: User) } class HomeRouter: HomeRoutingLogic { // 弱引用避免循环引用 weak var viewController: HomeViewController? func navigateToDetail(with user: User) { // 直接实例化目标VC(如果是xib创建,可替换为init(nibName:bundle:)) let detailVC = DetailViewController() // 直接给目标VC的属性赋值传递数据 detailVC.user = user // 执行导航操作(这里用push,也可以换成present) viewController?.navigationController?.pushViewController(detailVC, animated: true) } }
3. HomeViewController实现
class HomeViewController: UIViewController { var router: HomeRoutingLogic? // 模拟要传递的数据 let sampleUser = User(id: 1, name: "John Doe") override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .lightGray title = "Home" // 初始化Router并关联当前VC router = HomeRouter() (router as? HomeRouter)?.viewController = self // 添加测试按钮(代码创建,无需Storyboard) let goToDetailBtn = UIButton(type: .system) goToDetailBtn.setTitle("Go to Detail", for: .normal) goToDetailBtn.addTarget(self, action: #selector(goToDetailTapped), for: .touchUpInside) goToDetailBtn.frame = CGRect(x: 100, y: 200, width: 200, height: 50) view.addSubview(goToDetailBtn) } @objc func goToDetailTapped() { // 调用Router的导航方法,传递数据 router?.navigateToDetail(with: sampleUser) } }
4. DetailViewController实现
class DetailViewController: UIViewController { // 接收传递过来的数据 var user: User? override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white // 使用传递的数据更新UI title = user?.name let infoLabel = UILabel(frame: CGRect(x: 50, y: 200, width: 300, height: 50)) infoLabel.text = "User ID: \(user?.id ?? 0)" infoLabel.textAlignment = .center view.addSubview(infoLabel) } }
进阶:贴合Clean Swift分层的写法
如果要严格遵循Clean Swift的Presenter驱动逻辑,可以把导航触发放在Presenter中:
// 定义Presenter协议 protocol HomePresentationLogic { func triggerDetailNavigation() } class HomePresenter: HomePresentationLogic { var router: HomeRoutingLogic? var user: User? func triggerDetailNavigation() { guard let user = user else { return } router?.navigateToDetail(with: user) } } // 修改HomeViewController的按钮点击方法 @objc func goToDetailTapped() { let presenter = HomePresenter() presenter.user = sampleUser presenter.router = router presenter.triggerDetailNavigation() }
这样整个流程完全符合Clean Swift的分层职责:VC负责UI交互,Presenter处理业务逻辑,Router专注导航和数据传递,全程不需要依赖Storyboard的Segue。
内容的提问来源于stack exchange,提问作者Sazzad Hissain Khan
相关产品推荐
相关产品推荐

