#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. Спасибо, что разъяснили это! Я создал два модуля, как вы сказали, и он работает так, как ожидалось.