Привет, читатель!
В предыдущей статье я рассказывал про VIP цикл архитектуры Clean Swift. Теперь мы затронем одну из самых важных тем — переход и передачу данных между сценами.
?
За логику навигации и передачи данных отвечает компонент Router, который является частью сцены (опционально конечно). Он иницилизируется во ViewController’e, вместе с Interactor’ом и Presenter’ом.
Router реализует два протокола — RoutingLogic и DataPassing, которые мы будем наполнять своим функционалом. RoutingLogic должен содержать в себе методы, отвечающие за переход к конкретной сцене. DataPassing содержит в себе переменную dataStore, которая ссылается на протокол DataStore. Interactor сцены реализует протокол DataStore и работает с, хранящимися в нем, переменными. Сам Router содержит ссылку на ViewController своей сцены.
Используя ссылку на ViewController, Router производит переход между сценами. Для этого можно использовать Segue или же создавать сцену, на которую нужно совершить переход, программно. Какой способ используется — не важно, нам главное иметь ссылку на экземпляр класса ViewController’a, на который мы совершаем переход.
Используя ссылку на DataStore мы будем совершать передачу данных из Interactor’а одной сцены в Interactor сцены, на которую переходим. И, как было сказано ранее, именно Router должен знать, как это делать.
Для примера, мы будем передавать текст из TextField в Label другой сцены. Рассмотрим два способа перехода между сценами — по Segue и программно.
Класс Router содержит 3 смысловые группы методов:
?
Если мы совершаем переход по Segue, к примеру, при нажатии на кнопку, то во ViewController’e мы должны переопределить метод prepare(for:sender:). Данное расширение позволит автоматически вызывать методы из Router’a по названию Segue’я.
Переопределение prepare(for:sender:) не является обязательным при работе с Segue. Вы можете исключить его из кода и вызывать performSegue(withIdentifier:sender:) в методе Router’a. Prepare нужен только в случае, если вам необходимо использовать Segue вместе с передачей данных.
Теперь мы наконец то подошли к самому интересному — к коду Router’a. Пример содержит комментарии, поэтому мы рассмотрим только ключевые моменты.
В данном Router’e мы работаем с двумя сценами — Home и Detail. Переход со сцены Home обрабатывается так же двумя способами — по Segue и программно. Данные передаются со сцены Home на сцену Detail.
Все методы в протоколе RoutingLogic должны именоваться по принципу routeToNAME, где NAME является названием Segue (Identifier), которое мы задаем при работе со Storyboard’ом. Это нужно не только для удобства и красоты использования, но и для нашего селектора методов в prepare(for:sender:) ViewController’a, который мы переопределяли ранее.
Так же в классе HomeRouter есть методы начинающиеся на navigateTo и passDataTo. Первые отвечают за логику перехода, а вторые за передачу данных. Методы navigateTo создаются только в том случае, если переход осуществляется программно.
В примере мы имеем метод routeToDetail(segue:). Параметр segue опциональный, т.к. в методе содержится реализация, которая позволяет вызывать его без использования Segue. В обоих случаях перехода мы получаем неопциональные значения нашего HomeViewController’a и HomeDataStore’a сцены Home, а так же ссылки на ViewController и DataStore сцены Detail. Здесь стоит обратить внимание на то, что detailDS является переменной и передается в метод passDataToDetail с помощью сквозного параметра (inout). Это важно, т.к. без inout нам придется помечать все протоколы DataStore как “возможно реализовать только классами” (protocol DetailDataStore: class), а из этого вытекает множество сложностей, в том числе захват сильных ссылок.
На этом все. Спасибо, что дочитали до конца! Ниже я оставлю ссылку на проект, если захотите опробовать статью в деле.
Ссылка на проект: github.com/AlekseyPleshkov/CleanSwiftRouter
Помощь в написании статьи: Bastien
В предыдущей статье я рассказывал про VIP цикл архитектуры Clean Swift. Теперь мы затронем одну из самых важных тем — переход и передачу данных между сценами.
?
Теория
За логику навигации и передачи данных отвечает компонент Router, который является частью сцены (опционально конечно). Он иницилизируется во ViewController’e, вместе с Interactor’ом и Presenter’ом.
Router реализует два протокола — RoutingLogic и DataPassing, которые мы будем наполнять своим функционалом. RoutingLogic должен содержать в себе методы, отвечающие за переход к конкретной сцене. DataPassing содержит в себе переменную dataStore, которая ссылается на протокол DataStore. Interactor сцены реализует протокол DataStore и работает с, хранящимися в нем, переменными. Сам Router содержит ссылку на ViewController своей сцены.
Используя ссылку на ViewController, Router производит переход между сценами. Для этого можно использовать Segue или же создавать сцену, на которую нужно совершить переход, программно. Какой способ используется — не важно, нам главное иметь ссылку на экземпляр класса ViewController’a, на который мы совершаем переход.
Используя ссылку на DataStore мы будем совершать передачу данных из Interactor’а одной сцены в Interactor сцены, на которую переходим. И, как было сказано ранее, именно Router должен знать, как это делать.
Практика
Для примера, мы будем передавать текст из TextField в Label другой сцены. Рассмотрим два способа перехода между сценами — по Segue и программно.
Класс Router содержит 3 смысловые группы методов:
- Методы из реализации RoutingLogic (routeTo)
- Методы, отвечающие за навигацию (navigateTo, переход без Segue)
- Методы, для передачи данных (passDataTo, если есть данные для передачи)
?
Если мы совершаем переход по Segue, к примеру, при нажатии на кнопку, то во ViewController’e мы должны переопределить метод prepare(for:sender:). Данное расширение позволит автоматически вызывать методы из Router’a по названию Segue’я.
Переопределение prepare(for:sender:) не является обязательным при работе с Segue. Вы можете исключить его из кода и вызывать performSegue(withIdentifier:sender:) в методе Router’a. Prepare нужен только в случае, если вам необходимо использовать Segue вместе с передачей данных.
Теперь мы наконец то подошли к самому интересному — к коду Router’a. Пример содержит комментарии, поэтому мы рассмотрим только ключевые моменты.
В данном Router’e мы работаем с двумя сценами — Home и Detail. Переход со сцены Home обрабатывается так же двумя способами — по Segue и программно. Данные передаются со сцены Home на сцену Detail.
Все методы в протоколе RoutingLogic должны именоваться по принципу routeToNAME, где NAME является названием Segue (Identifier), которое мы задаем при работе со Storyboard’ом. Это нужно не только для удобства и красоты использования, но и для нашего селектора методов в prepare(for:sender:) ViewController’a, который мы переопределяли ранее.
Так же в классе HomeRouter есть методы начинающиеся на navigateTo и passDataTo. Первые отвечают за логику перехода, а вторые за передачу данных. Методы navigateTo создаются только в том случае, если переход осуществляется программно.
В примере мы имеем метод routeToDetail(segue:). Параметр segue опциональный, т.к. в методе содержится реализация, которая позволяет вызывать его без использования Segue. В обоих случаях перехода мы получаем неопциональные значения нашего HomeViewController’a и HomeDataStore’a сцены Home, а так же ссылки на ViewController и DataStore сцены Detail. Здесь стоит обратить внимание на то, что detailDS является переменной и передается в метод passDataToDetail с помощью сквозного параметра (inout). Это важно, т.к. без inout нам придется помечать все протоколы DataStore как “возможно реализовать только классами” (protocol DetailDataStore: class), а из этого вытекает множество сложностей, в том числе захват сильных ссылок.
На этом все. Спасибо, что дочитали до конца! Ниже я оставлю ссылку на проект, если захотите опробовать статью в деле.
Серия статей
- Общее представление об архитектуре Clean Swift
- Router и Data Passing в архитектуре Clean Swift (вы здесь)
- Workers в архитектуре Clean Swift
- Тестирование приложения на архитектуре Clean Swift
- Пример простого интернет-магазина на архитектуре Clean Swift
Ссылка на проект: github.com/AlekseyPleshkov/CleanSwiftRouter
Помощь в написании статьи: Bastien
mbabaev
Не нравится удвоение кода в месте, где мы смотрим перешли ли мы по segue или сами. Кажется, что лучше договориться внутри проекта переходить на экраны только через segue/только программно. Тогда будет лучше и для быстрого понимания где искать переход на другой экран, и меньше кода в роутере.
AlekseyPleshkov Автор
Да, все верно, в команде нужно заранее обговорить, какой тип перехода будет использоваться. В статье я показал «как можно сделать», а так нужно для себя решить «как будет».