Несколько контроллеров просмотра в одном модуле VIPER

#ios #swift #architecture #viper-architecture

Вопрос:

Я создаю свое первое приложение, используя архитектуру VIPER. У меня есть два VC: основной и модальный (представленный модально из основного VC). Внутри моего модального VC есть просмотр таблицы, и когда пользователь выбирает там строку, мне нужно передать ее ведущему, а затем от ведущего к основному 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
    }
    
}
 

viewDidLoad() в главном ВК:

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

viewDidLoad() в модальном VC:

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

В любом случае, я не уверен, что это соответствует принципам ГАДЮКИ. Так ли это, или есть лучшие решения? Любая помощь будет признательна!

Ответ №1:

Если вы собираетесь представить другой контроллер представления, он должен быть на своем собственном модуле для 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 модуля, ObserverModule и CurrenciesModule , которые должны иметь двунаправленное соединение через свои маршрутизаторы. Поскольку маршрутизаторы отвечают за представление/отклонение представлений (и они поддерживают соединение со своими представлениями), они могут обновлять свои представления и/или разрешать одноранговому маршрутизатору обновлять свои собственные представления.

Комментарии:

1. Спасибо, что разъяснили это! Я создал два модуля, как вы сказали, и он работает так, как ожидалось.