Skip to content

16.2_由ViewModel发起导航请求

在 MVVM 架构中,ViewModel 负责处理业务逻辑,但不直接操作 UI。因此,当 ViewModel 需要进行页面跳转时,它会发起一个导航请求,而不是直接调用 UIKit 的导航方法。这种方式解耦了 ViewModel 和 View,提高了代码的可测试性和可维护性。让我们一起看看如何实现吧!🚀

ViewModel 如何发出导航请求

ViewModel 通常会定义一个属性,用于发出导航请求。这个属性可以是一个闭包,一个 Delegate,或者一个 ReactiveCocoa Signal。当 ViewModel 需要导航时,它会触发这个属性,并传递导航所需的数据。

例如,你可以使用闭包:

swift
var navigateToDetail: ((Item) -> Void)?

当 ViewModel 需要导航到详情页时,它可以这样调用:

swift
navigateToDetail?(item)

导航请求的数据传递

ViewModel 发出的导航请求通常需要携带一些数据,例如要显示的 Item 的 ID。这些数据可以通过闭包的参数传递,或者通过 Delegate 方法的参数传递。

例如,如果使用闭包,你可以这样定义:

swift
var navigateToDetail: ((Item) -> Void)?

当 ViewModel 需要导航到详情页时,它可以这样调用:

swift
let item = Item(id: 1, name: "示例项目")
navigateToDetail?(item)

导航请求的响应

ViewController 或 Coordinator 负责监听 ViewModel 发出的导航请求,并执行实际的页面跳转。ViewController 可以直接监听 ViewModel 的属性,或者通过 Delegate 协议接收通知。Coordinator 则可以作为 ViewModel 的 Delegate,负责处理所有的导航请求。

例如,在 ViewController 中,你可以这样监听 ViewModel 的 navigateToDetail 属性:

swift
viewModel.navigateToDetail = { [weak self] item in
    let detailViewController = DetailViewController(item: item)
    self?.navigationController?.pushViewController(detailViewController, animated: true)
}

示例:使用 Delegate 发起导航请求

  1. 定义 Delegate 协议:首先,定义一个协议,用于 ViewModel 通知导航事件。

    swift
    protocol ListViewModelNavigationDelegate: AnyObject {
        func didSelectItem(item: Item)
    }
  2. ViewModel 持有 Delegate:ViewModel 声明一个 weak 类型的 Delegate 属性。

    swift
    class ListViewModel {
        weak var navigationDelegate: ListViewModelNavigationDelegate?
    }
  3. 触发 Delegate 方法:当 ViewModel 需要导航时,调用 Delegate 方法。

    swift
    func didSelectRow(at indexPath: IndexPath) {
        let item = items[indexPath.row]
        navigationDelegate?.didSelectItem(item: item)
    }
  4. ViewController 实现 Delegate:ViewController 实现 Delegate 协议,并执行页面跳转。

    swift
    extension ListViewController: ListViewModelNavigationDelegate {
        func didSelectItem(item: Item) {
            let detailViewController = DetailViewController(item: item)
            navigationController?.pushViewController(detailViewController, animated: true)
        }
    }

通过以上步骤,你就可以实现 ViewModel 发起导航请求,并由 ViewController 或 Coordinator 响应并执行页面跳转。这种方式可以有效地解耦 ViewModel 和 View,提高代码的可测试性和可维护性。🎉

本站使用 VitePress 制作