16.2_由ViewModel发起导航请求
在 MVVM 架构中,ViewModel 负责处理业务逻辑,但不直接操作 UI。因此,当 ViewModel 需要进行页面跳转时,它会发起一个导航请求,而不是直接调用 UIKit 的导航方法。这种方式解耦了 ViewModel 和 View,提高了代码的可测试性和可维护性。让我们一起看看如何实现吧!🚀
ViewModel 如何发出导航请求
ViewModel 通常会定义一个属性,用于发出导航请求。这个属性可以是一个闭包,一个 Delegate,或者一个 ReactiveCocoa Signal。当 ViewModel 需要导航时,它会触发这个属性,并传递导航所需的数据。
例如,你可以使用闭包:
var navigateToDetail: ((Item) -> Void)?当 ViewModel 需要导航到详情页时,它可以这样调用:
navigateToDetail?(item)导航请求的数据传递
ViewModel 发出的导航请求通常需要携带一些数据,例如要显示的 Item 的 ID。这些数据可以通过闭包的参数传递,或者通过 Delegate 方法的参数传递。
例如,如果使用闭包,你可以这样定义:
var navigateToDetail: ((Item) -> Void)?当 ViewModel 需要导航到详情页时,它可以这样调用:
let item = Item(id: 1, name: "示例项目")
navigateToDetail?(item)导航请求的响应
ViewController 或 Coordinator 负责监听 ViewModel 发出的导航请求,并执行实际的页面跳转。ViewController 可以直接监听 ViewModel 的属性,或者通过 Delegate 协议接收通知。Coordinator 则可以作为 ViewModel 的 Delegate,负责处理所有的导航请求。
例如,在 ViewController 中,你可以这样监听 ViewModel 的 navigateToDetail 属性:
viewModel.navigateToDetail = { [weak self] item in
let detailViewController = DetailViewController(item: item)
self?.navigationController?.pushViewController(detailViewController, animated: true)
}示例:使用 Delegate 发起导航请求
定义 Delegate 协议:首先,定义一个协议,用于 ViewModel 通知导航事件。
swiftprotocol ListViewModelNavigationDelegate: AnyObject { func didSelectItem(item: Item) }ViewModel 持有 Delegate:ViewModel 声明一个
weak类型的 Delegate 属性。swiftclass ListViewModel { weak var navigationDelegate: ListViewModelNavigationDelegate? }触发 Delegate 方法:当 ViewModel 需要导航时,调用 Delegate 方法。
swiftfunc didSelectRow(at indexPath: IndexPath) { let item = items[indexPath.row] navigationDelegate?.didSelectItem(item: item) }ViewController 实现 Delegate:ViewController 实现 Delegate 协议,并执行页面跳转。
swiftextension ListViewController: ListViewModelNavigationDelegate { func didSelectItem(item: Item) { let detailViewController = DetailViewController(item: item) navigationController?.pushViewController(detailViewController, animated: true) } }
通过以上步骤,你就可以实现 ViewModel 发起导航请求,并由 ViewController 或 Coordinator 响应并执行页面跳转。这种方式可以有效地解耦 ViewModel 和 View,提高代码的可测试性和可维护性。🎉