Skip to content

11.4_路由(Routing)与导航逻辑的抽离

为什么需要抽离路由与导航逻辑?

在MVVM架构中,保持View和ViewModel的职责分离至关重要。如果将导航逻辑直接放在ViewModel中,ViewModel就会对特定的View控制器产生依赖,这会大大降低其可重用性和可测试性。想象一下,一个ViewModel需要知道如何呈现一个用户详情页,这会使其变得臃肿且难以维护。抽离路由与导航逻辑,能让你的代码更清晰、更模块化。 🚀

路由器的核心概念

路由器(Router)是一个专门负责处理应用内导航的独立组件。它接收导航请求,并根据这些请求决定要呈现哪个View控制器。通过引入路由器,ViewModel不再需要直接与View控制器交互,而是将导航意图传递给路由器。这就像一个交通指挥官,ViewModel只发出“去哪里”的指令,而路由器则负责“怎么去”。

如何实现一个简单的路由器

实现一个路由器通常涉及定义一个协议和具体的实现类。这个协议会定义所有可能的导航操作。例如,你可能需要导航到用户列表、用户详情或设置页面。

swift
protocol AppRouter: AnyObject {
    func navigateToUserList()
    func navigateToUserDetails(userId: String)
    func navigateToSettings()
}

然后,你可以创建一个具体的路由器类,它会持有当前导航栈的引用,并负责实例化和呈现View控制器。

swift
class MainAppRouter: AppRouter {
    weak var navigationController: UINavigationController?

    init(navigationController: UINavigationController?) {
        self.navigationController = navigationController
    }

    func navigateToUserList() {
        let viewModel = UserListViewModel(router: self)
        let viewController = UserListViewController(viewModel: viewModel)
        navigationController?.pushViewController(viewController, animated: true)
    }

    func navigateToUserDetails(userId: String) {
        let viewModel = UserDetailsViewModel(userId: userId, router: self)
        let viewController = UserDetailsViewController(viewModel: viewModel)
        navigationController?.pushViewController(viewController, animated: true)
    }

    func navigateToSettings() {
        let viewModel = SettingsViewModel(router: self)
        let viewController = SettingsViewController(viewModel: viewModel)
        navigationController?.pushViewController(viewController, animated: true)
    }
}

ViewModel如何与路由器交互

ViewModel不再直接调用presentpushViewController。相反,它会通过其持有的AppRouter实例来请求导航。

例如,在一个用户列表ViewModel中,当用户点击某个用户时,ViewModel会调用路由器的navigateToUserDetails方法:

swift
class UserListViewModel {
    private let router: AppRouter

    init(router: AppRouter) {
        self.router = router
    }

    func didSelectUser(userId: String) {
        router.navigateToUserDetails(userId: userId)
    }
}

这种方式极大地提升了ViewModel的独立性。它不再关心具体的导航实现,只关注业务逻辑。

路由器的优势与最佳实践

抽离路由与导航逻辑带来了诸多好处:

  • 提高可测试性:ViewModel可以独立于UI进行测试,因为导航逻辑被抽象出来。你可以轻松地模拟路由器,验证ViewModel的导航意图。
  • 增强模块化:导航逻辑集中在一个地方,使得代码结构更加清晰,易于理解和维护。
  • 提升可重用性:ViewModel不再依赖特定的View控制器,可以在不同的应用场景中复用。
  • 灵活的导航策略:你可以轻松地修改导航行为,例如从push改为present,而无需修改ViewModel。

在实践中,你可以考虑以下几点:

  1. 依赖注入:通过依赖注入将路由器传递给ViewModel,确保ViewModel不直接创建路由器实例。
  2. 协议驱动:始终使用协议来定义路由器接口,这有助于解耦和测试。
  3. 避免循环引用:确保路由器和View控制器之间的引用关系不会导致内存泄漏,通常使用weak引用。

通过这些实践,你的iOS应用将拥有更健壮、更易于维护的导航系统! 🌟

本站使用 VitePress 制作