Home > Blockchain >  Multiple View Controllers in a single VIPER module
Multiple View Controllers in a single VIPER module

Time:09-22

I'm building my first app using VIPER architecture. I have two VCs: the main one and the modal one (presented modally from the main VC). There is a tableView inside my modal VC, and when the user selects a row there, I need to pass it to presenter and then from presenter to the main VC. I also need to keep the selected row highlighted in the modal VC, so if I close it and then present it again, the row will be still highlighted. I'm confused, because I don't know what's the best way to do it. What I've tried is including my modal VC into configurator and calling configurator two times: in the main VC and then again in the modal VC. It works fine. That's what my configurator looks like:

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
    }
    
}

viewDidLoad() in the main VC:

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

viewDidLoad() in the modal VC:

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

Anyway, I'm not sure it corresponds VIPER principles. Does it, or there are better solutions? Any help is appreciated!

CodePudding user response:

If you are going to present another view controller, it should be on its own module for VIPER. ObserverViewController should not know about the presence of CurrenciesViewController.

Instead, only ObserverRouter should know about how to build CurrenciesModule and present and pass data into it. Something like this:

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
    }
}

So, whenever you need to present CurrenciesViewController, you could pass selectedIndex and it can highlight it, if applicable. I would pass the information to the interactor, and let presenter know about it and do some changes in the view.

For passing the selectedIndex back to ObserverViewController, you could create a ObserverRouterDelegate that can be triggered when CurrenciesViewController is going to be dismissed.

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

To wrap up; there should be 2 modules, ObserverModule and CurrenciesModule, that should have bidirectional connection through their routers. Since routers are responsible for presenting/dismissing views (and they hold a connection to their views), they can update their views and/or let the peer router update their own views.

  • Related