单个 VIPER 模块中的多个视图控制器

Multiple View Controllers in a single VIPER module

我正在使用 VIPER 架构构建我的第一个应用程序。我有两个 VCs:主要的和模态的(从主要 VC 模态呈现)。我的模式 VC 中有一个 tableView,当用户在那里选择一行时,我需要将它传递给演示者,然后从演示者传递给主 VC。我还需要在模态 VC 中保持所选行突出显示,因此如果我关闭它然后再次显示它,该行仍将突出显示。我很困惑,因为我不知道最好的方法是什么。我尝试过的是将模态 VC 包含到配置器中并调用配置器两次:在主 VC 中,然后在模态 VC 中再次调用。它工作正常。这就是我的配置器的样子:

protocol ObserverConfiguratorProtocol {
    func configure(with mainViewController: ObserverViewController, with modalViewController: CurrenciesViewController)
}

class ObserverConfigurator: ObserverConfiguratorProtocol {
    
    func configure(with mainViewController: ObserverViewController, with modalViewController: CurrenciesViewController) {
        
        let presenter = ObserverPresenter(view: mainViewController)
        let interactor = ObserverInteractor(presenter: presenter)
        let router = ObserverRouter(view: mainViewController)
        
        mainViewController.presenter = presenter
        modalViewController.presenter = presenter
        
        presenter.interactor = interactor
        presenter.router = router
        presenter.view = mainViewController
        presenter.modalView = modalViewController
    }
    
}

主要 VC:

中的 viewDidLoad()
  override func viewDidLoad() {
        configurator.configure(with: self, view: CurrenciesViewController())
    }

模态 VC:

中的 viewDidLoad()
  override func viewDidLoad() {
        configurator.configure(with: ObserverViewController(), view: self)
    }

无论如何,我不确定它是否符合 VIPER 原则。是吗,或者有更好的解决方案?感谢您的帮助!

如果您要展示另一个视图控制器,它应该位于 VIPER 自己的模块中。 ObserverViewController 不应该知道 CurrenciesViewController 的存在。

相反,只有 ObserverRouter 应该知道如何构建 CurrenciesModule 并向其中呈现和传递数据。像这样:

final class CurrenciesBuilder {
    @available(*, unavailable) private init() { }

    static func build(routerDelegate: ObserverRouterDelegate, selectedIndex: IndexPath?) -> CurrenciesViewProtocol {
        let service = CurrenciesService()
        let interactor = CurrenciesInteractor(service: service, selectedIndex: selectedIndex)

        let view = CurrenciesViewController(nibName: String(describing: CurrenciesViewController.self), bundle: nil)
        let router = CurrenciesRouter(vc: view)
        router.delegate = routerDelegate

        let presenter = CurrenciesPresenter(interactor: interactor,
                                            view: view,
                                            router: router)
        view.presenter = presenter

        return view
    }
}

因此,每当您需要显示 CurrenciesViewController 时,您可以传递 selectedIndex 并且它可以突出显示它(如果适用)。我会将信息传递给交互器,让演示者知道并在视图中做一些更改。

为了将 selectedIndex 传回 ObserverViewController,您可以创建一个 ObserverRouterDelegate,它可以在 CurrenciesViewController 将被关闭时触发。

protocol ObserverRouterDelegate: AnyObject {
    func didDismiss(with selectedIndex: IndexPath?)
}

总结;应该有 2 个模块,ObserverModuleCurrenciesModule,它们应该通过它们的路由器进行双向连接。由于路由器负责 presenting/dismissing 视图(并且它们与它们的视图保持连接),它们可以更新它们的视图 and/or 让对等路由器更新它们自己的视图。