Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Роутинг в Clean Swift (VIP-цикл)
В Clean Swift архитектуре за роутинг отвечает отдельный компонент под названием Router. Его основная задача — управление переходами между сценами (ViewController'ами) и передачей данных между ними, следуя принципу однонаправленного потока данных VIP-цикла.
Роль Router в VIP-цикле
Router является конечной точкой взаимодействия внутри сцены. Он получает управление после того, как Presenter обновит ViewController, и решает, нужно ли выполнить навигационный переход. Ключевые аспекты:
- Инкапсуляция навигационной логики: Все переходы (push, modal, pop, unwind) выносятся в Router, что делает ViewController "тупым" и переиспользуемым.
- Работа с Data Passing: Router отвечает за передачу данных Data Store следующей сцене через Data Passing протокол.
- Изоляция зависимости от UIKit: Навигация, жестко завязанная на UIKit (например,
UINavigationController.pushViewController), абстрагируется в Router, что упрощает тестирование.
Как работает Router: код и поток данных
Рассмотрим на примере перехода от сцены "Список статей" к "Детали статьи":
- Interactor обрабатывает tap по ячейке, готовит данные (например, ID статьи) и передает их во ViewController через Presenter.
- Presenter форматирует данные в ViewModel и триггерит событие перехода.
- ViewController получает ViewModel и вызывает метод Router'а для перехода.
// Протокол для передачи данных МЕЖДУ сценами
protocol ArticleDetailDataPassing {
var dataStore: ArticleDetailDataStore? { get }
}
// Router для сцены "Список статей"
protocol ArticleListRoutingLogic {
func routeToArticleDetail()
}
final class ArticleListRouter: ArticleListRoutingLogic, ArticleDetailDataPassing {
weak var viewController: ArticleListViewController?
var dataStore: ArticleDetailDataStore? // Data Store следующей сцены
// MARK: - Routing
func routeToArticleDetail() {
// 1. Получаем DataStore текущей сцены
guard let sourceDS = viewController?.interactor as? ArticleListDataStore,
let detailVC = ArticleDetailViewController() as? ArticleDetailViewController else { return }
// 2. Настраиваем Data Passing
var destinationDS = detailVC.router?.dataStore
destinationDS?.articleID = sourceDS.selectedArticleID // Передаем данные
// 3. Выполняем переход (навигация)
viewController?.navigationController?.pushViewController(detailVC, animated: true)
}
}
Ключевые паттерны и best practices
- Data Passing через протоколы: Каждая сцена объявляет протокол
[SceneName]DataPassing, который включаетdataStoreследующей сцены. Это обеспечивает строгую типизацию. - Router не содержит бизнес-логики: Он только маршрутизирует и передает данные. Решение "куда" перейти часто принимается во ViewController на основе ViewModel от Presenter'а.
- Использование Segue (опционально): В Clean Swift можно использовать Storyboard Segue, но тогда Router конфигурирует
prepare(for:sender:), изолируя эту логику от ViewController. - Слабая связь: Router хранит weak ссылку на ViewController, чтобы избежать retain cycle.
- Тестируемость: Благодаря протоколам, Router легко замокать в unit-тестах Interactor'а или Presenter'а.
Отличие от обычного MVC и других архитектур
В классическом MVC навигация часто размазана между ViewController'ами, что приводит к Massive ViewController. Clean Swift решает это через Router, делая навигацию:
- Предсказуемой: все переходы в одном месте.
- Модифицируемой: изменение типа перехода (например, с push на modal) затрагивает только Router.
- Безопасной: компилятор проверяет Data Passing через протоколы.
Итог: Router в Clean Swift — это централизованный, тестируемый менеджер навигации, который строго отделяет переходы между экранами от бизнес-логики и представления, следуя принципам Clean Architecture и SOLID.