MVVM结合RxSwift实现ViewController导航:求简便Segue跳转方案
MVVM + RxSwift 下更简便的 ViewController Segue 跳转方式?
提问内容:
我正在用 MVVM 架构结合 RxSwift 做开发,之前试过用 Coordinator 和 RxFlow 来处理 ViewController 之间的导航,但感觉有点重。想问问有没有更简便的方式,直接通过 RxSwift 来实现 ViewController 间的 Segue 跳转?
以下是我目前的常规实现代码:
viewModel.users.subscribe { model in self.walkthrough = WalkthroughModel(country: (model.element?.country)!, countryCode: (model.element?.countryCode)!,PhoneNumber:"") DispatchQueue.main.async { self.performSegue(withIdentifier: "Walkthrough_phone", sender: self) } }.disposed(by: disposeBag)
回答:
当然有更简洁的方式!其实我们可以把 Segue 的触发逻辑和 RxSwift 的响应式流结合得更紧密,既符合 MVVM 的职责分离,又能减少冗余代码。下面给你两种实用方案:
方案1:封装 Rx 扩展,让跳转逻辑可复用
我们可以给 UIViewController 写一个 Rx 扩展,把 Segue 触发转化为可绑定的信号,这样 ViewModel 只需要输出跳转事件,ViewController 负责绑定响应就行,代码更清爽:
import RxSwift import RxCocoa extension UIViewController { // 无参数的Segue绑定 func rx_performSegue(withIdentifier identifier: String) -> Binder<Void> { return Binder(self) { vc, _ in vc.performSegue(withIdentifier: identifier, sender: vc) } } // 带参数的Segue绑定,同时处理参数传递 func rx_performSegue<T>(withIdentifier identifier: String, prepare: @escaping (T) -> Void) -> Binder<T> { return Binder(self) { vc, parameter in prepare(parameter) vc.performSegue(withIdentifier: identifier, sender: vc) } } }
然后在你的 ViewController 里这么用:
// 先在ViewModel里定义一个跳转输出流(示例) // let navigateToWalkthrough = PublishSubject<WalkthroughModel>() // ViewController里绑定信号 viewModel.navigateToWalkthrough .observe(on: MainScheduler.instance) // 确保UI操作在主线程 .bind(to: self.rx_performSegue(withIdentifier: "Walkthrough_phone") { [weak self] model in self?.walkthrough = model }) .disposed(by: disposeBag)
这种方式的好处是把跳转逻辑模块化,后续其他页面的Segue跳转都可以复用这个扩展,而且ViewModel只负责业务逻辑和事件分发,完全不涉及UI操作,更贴合MVVM的设计。
方案2:直接优化现有代码,减少冗余
如果不想写扩展,也可以直接改造你现有的代码,解决冗余和安全问题:
viewModel.users .compactMap { $0 } // 自动过滤nil元素,避免强制解包 .observe(on: MainScheduler.instance) // 统一指定主线程,不用手动写DispatchQueue .subscribe(onNext: { [weak self] model in guard let self = self else { return } // 这里直接用model的属性,不用强制解包 self.walkthrough = WalkthroughModel(country: model.country, countryCode: model.countryCode, phoneNumber: "") self.performSegue(withIdentifier: "Walkthrough_phone", sender: self) }) .disposed(by: disposeBag)
这里做了几个优化:
- 用
compactMap过滤掉nil的元素,避免后续强制解包崩溃 - 用
observe(on: MainScheduler.instance)统一切换到主线程,替代手动的DispatchQueue.main.async - 用
[weak self]和guard let避免循环引用,代码更安全
为什么这些方式更简便?
- 摆脱了在subscribe闭包里写大量UI逻辑的混乱,符合响应式编程的思想
- 代码更安全,避免强制解包和线程切换的冗余代码
- 第一种方案的扩展可以复用,后续新增跳转逻辑成本更低
内容的提问来源于stack exchange,提问作者Guru Charan
相关产品推荐
相关产品推荐

