You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Viper模块模板无视图关联,如何实现页面导航?

在未建立视图关联的Viper模板中实现页面导航

我下载了Viper模块模板,但该模板未建立视图关联,请问如何在此基础上实现页面导航?我是否可以通过简便方式获取视图引用?比如在Router中调用view.goToAnotherScreen这类定义在ViewController中的方法?

Scene Delegate 代码

let startModule = CardsCollectionRouter.createModule()
let navigationController = UINavigationController(rootViewController: startModule)
window?.rootViewController = navigationController
window?.makeKeyAndVisible()

Router 代码

class CardsCollectionRouter: PresenterToRouterCardsCollectionProtocol {
    
    // MARK: Static methods
    static func createModule() -> UIViewController {
        
        let viewController = CardsCollectionViewController()
        let presenter: ViewToPresenterCardsCollectionProtocol & InteractorToPresenterCardsCollectionProtocol = CardsCollectionPresenter()
        let networkService = NetworkService()
        
        viewController.presenter = presenter
        viewController.presenter?.router = CardsCollectionRouter()
        viewController.presenter?.view = viewController
        viewController.presenter?.interactor = CardsCollectionInteractor(networkService: networkService)
        viewController.presenter?.interactor?.presenter = presenter
        
        return viewController
    }
    
    func showDescription(description: CharacterModel?) {
        let descriptionVC = DescripModuleRouter.createModule(description: description)
        //How to go on next screen??
        let viewController = CardsCollectionViewController()
        viewController.navigationController?.pushViewController(descriptionVC, animated: true)
    }
}

解决方案

1. 修复当前导航失效的问题

你现在的showDescription方法里新建了一个CardsCollectionViewController实例,这不是当前正在显示的控制器,所以navigationController会是nil,push操作自然不生效。正确的做法是让Router持有当前控制器的引用:

修改Router代码如下:

class CardsCollectionRouter: PresenterToRouterCardsCollectionProtocol {
    // 用weak避免循环引用
    weak var viewController: CardsCollectionViewController?
    
    // MARK: Static methods
    static func createModule() -> UIViewController {
        let viewController = CardsCollectionViewController()
        let presenter: ViewToPresenterCardsCollectionProtocol & InteractorToPresenterCardsCollectionProtocol = CardsCollectionPresenter()
        let networkService = NetworkService()
        // 创建Router实例并绑定当前控制器
        let router = CardsCollectionRouter()
        router.viewController = viewController
        
        viewController.presenter = presenter
        presenter.router = router
        presenter.view = viewController
        presenter.interactor = CardsCollectionInteractor(networkService: networkService)
        presenter.interactor?.presenter = presenter
        
        return viewController
    }
    
    func showDescription(description: CharacterModel?) {
        let descriptionVC = DescripModuleRouter.createModule(description: description)
        // 使用持有的当前控制器进行push
        viewController?.navigationController?.pushViewController(descriptionVC, animated: true)
    }
}

2. 关于调用ViewController的自定义导航方法

这种方式是可行的,但不符合VIPER的职责划分——Router的核心职责就是处理页面导航逻辑,ViewController只应该负责视图渲染和把用户交互事件传递给Presenter。如果一定要这么做,在Router持有viewController引用后可以直接调用:

// 在ViewController里定义方法
extension CardsCollectionViewController {
    func goToAnotherScreen(_ vc: UIViewController) {
        navigationController?.pushViewController(vc, animated: true)
    }
}

// 在Router的showDescription里调用
viewController?.goToAnotherScreen(descriptionVC)

但还是更推荐让Router来处理导航,保持各模块职责清晰。


内容的提问来源于stack exchange,提问作者kesape

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 18:31:08