Upload
avitotech
View
308
Download
1
Embed Size (px)
Citation preview
Удобный и расширяемый роутинг в iOS-приложении
Юсипов Тимур
Avito
Историческая справка
70187 lines of code
39051 lines of code
(2011 .. 2013) Outsource(2013 .. 2016) In-house
VIPER
Введем понятие Router
Как будет проходить презентация?
Рассмотрим необычные задачи Routing’а
Попробуем написать RouterАдаптируем Router под iPadСформулируем общие архитектурные правила Routing’а
Посмотрим демо
Что такое Module?
Router
View Controller
MVC
Model View View Interactor
Router
Presenter Entity
VIPER
RouterRouter
View Controller
MVC
Model View View InteractorPresenter Entity
VIPER
Что такое DeepLink?
ru.navigation.demo://categories?categoryId=182
ru.navigation.demo://authorize
ru.navigation.demo://search?categoryId=182&query=mazda
presentation.start()
final class ViewController: UIViewController { @objc private func onAuthorizationButtonTap(sender: UIBarButtonItem) { let authorizationController = AuthorizationViewController()
let navigationController = UINavigationController( rootViewController: authorizationController ) presentViewController(navigationController, animated: true, completion: nil) } }
Что не так с этим кодом?final class ViewController: UIViewController { @objc private func onAuthorizationButtonTap(sender: UIBarButtonItem) { let authorizationController = AuthorizationViewController()
let navigationController = UINavigationController( rootViewController: authorizationController ) presentViewController(navigationController, animated: true, completion: nil) } }
final class ViewController: UIViewController { @objc private func onAuthorizationButtonTap(sender: UIBarButtonItem) { let authorizationController = AuthorizationViewController()
let navigationController = UINavigationController( rootViewController: authorizationController ) presentViewController(navigationController, animated: true, completion: nil) } }
final class ViewController: UIViewController { @objc private func onAuthorizationButtonTap(sender: UIBarButtonItem) { let authorizationController = AuthorizationViewController()
let navigationController = UINavigationController( rootViewController: authorizationController ) presentViewController(navigationController, animated: true, completion: nil) } }
final class ViewController: UIViewController { @objc private func onAuthorizationButtonTap(sender: UIBarButtonItem) { let authorizationController = AuthorizationViewController()
let navigationController = UINavigationController( rootViewController: authorizationController ) presentViewController(navigationController, animated: true, completion: nil) } }
Добавим слой Router
protocol RouterProtocol: class { func showAuthorization() }
Пробуем написать Routerprotocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: RouterProtocol { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? func showAuthorization() { let authorizationController = AuthorizationViewController() let router = AuthorizationRouterImpl() router.navigationController = navigationController router.rootViewController = authorizationController authorizationController.router = router navigationController?.pushViewController(authorizationController, animated: true) } }
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: RouterProtocol { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? func showAuthorization() { let authorizationController = AuthorizationViewController() let router = AuthorizationRouterImpl() router.navigationController = navigationController router.rootViewController = authorizationController authorizationController.router = router navigationController?.pushViewController(authorizationController, animated: true) } }
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: RouterProtocol { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? func showAuthorization() { let authorizationController = AuthorizationViewController() let router = AuthorizationRouterImpl() router.navigationController = navigationController router.rootViewController = authorizationController authorizationController.router = router navigationController?.pushViewController(authorizationController, animated: true) } }
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: RouterProtocol { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? func showAuthorization() { let authorizationController = AuthorizationViewController() let router = AuthorizationRouterImpl() router.navigationController = navigationController router.rootViewController = authorizationController authorizationController.router = router navigationController?.pushViewController(authorizationController, animated: true) } }
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: RouterProtocol { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? func showAuthorization() { let authorizationController = AuthorizationViewController() let router = AuthorizationRouterImpl() router.navigationController = navigationController router.rootViewController = authorizationController authorizationController.router = router navigationController?.pushViewController(authorizationController, animated: true) } }
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: RouterProtocol { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? func showAuthorization() { let authorizationController = AuthorizationViewController() let router = AuthorizationRouterImpl() router.navigationController = navigationController router.rootViewController = authorizationController authorizationController.router = router navigationController?.pushViewController(authorizationController, animated: true) } }
Добавим слой Assembly
Добавляем слой Assemblyprotocol AssemblyFactory: class { func authorizationAssembly() -> AuthorizationAssembly }
protocol AssemblyFactory: class { func authorizationAssembly() -> AuthorizationAssembly }
protocol AuthorizationAssembly: class { func module(navigationController: UINavigationController) -> UIViewController }
protocol AssemblyFactory: class { func authorizationAssembly() -> AuthorizationAssembly }
protocol AuthorizationAssembly: class { func module(navigationController: UINavigationController) -> UIViewController }
Пробуем написать Router c Assemblyprotocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: RouterProtocol { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? let assemblyFactory: AssemblyFactory
func showAuthorization() { let authorizationController = AuthorizationViewController() let router = AuthorizationRouterImpl() router.navigationController = navigationController router.rootViewController = authorizationController authorizationController.router = router navigationController?.pushViewController(authorizationController, animated: true) } }
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: RouterProtocol { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? let assemblyFactory: AssemblyFactory func showAuthorization() { let authorizationController = AuthorizationViewController() let router = AuthorizationRouterImpl() router.navigationController = navigationController router.rootViewController = authorizationController authorizationController.router = router navigationController?.pushViewController(authorizationController, animated: true) } }
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: RouterProtocol { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? let assemblyFactory: AssemblyFactory
func showAuthorization() { if let navigationController = navigationController { let authorizationAssembly = assemblyFactory.authorizationAssembly() let authorizationController = authorizationAssembly.module(navigationController) navigationController.pushViewController(authorizationController, animated: true) } } }
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: RouterProtocol { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? let assemblyFactory: AssemblyFactory func showAuthorization() { if let navigationController = navigationController { let authorizationAssembly = assemblyFactory.authorizationAssembly() let authorizationController = authorizationAssembly.module(navigationController) navigationController.pushViewController(authorizationController, animated: true) } } }
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: RouterProtocol { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? let assemblyFactory: AssemblyFactory func showAuthorization() { if let navigationController = navigationController { let authorizationAssembly = assemblyFactory.authorizationAssembly() let authorizationController = authorizationAssembly.module(navigationController) navigationController.pushViewController(authorizationController, animated: true) } } }
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: RouterProtocol { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? let assemblyFactory: AssemblyFactory func showAuthorization() { if let navigationController = navigationController { let authorizationAssembly = assemblyFactory.authorizationAssembly() let authorizationController = authorizationAssembly.module(navigationController) navigationController.pushViewController(authorizationController, animated: true) } } }
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: RouterProtocol { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? let assemblyFactory: AssemblyFactory func showAuthorization() { if let navigationController = navigationController { let authorizationAssembly = assemblyFactory.authorizationAssembly() let authorizationController = authorizationAssembly.module(navigationController) navigationController.pushViewController(authorizationController, animated: true) } } }
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: RouterProtocol { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? let assemblyFactory: AssemblyFactory func showAuthorization() { if let navigationController = navigationController { let authorizationAssembly = assemblyFactory.authorizationAssembly() let authorizationController = authorizationAssembly.module(navigationController) navigationController.pushViewController(authorizationController, animated: true) } } }
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: RouterProtocol { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? let assemblyFactory: AssemblyFactory func showAuthorization() { if let navigationController = navigationController { let authorizationAssembly = assemblyFactory.authorizationAssembly() let authorizationController = authorizationAssembly.module(navigationController) navigationController.pushViewController(authorizationController, animated: true) } } }
Добавим базовый класс
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: RouterProtocol { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? let assemblyFactory: AssemblyFactory func showAuthorization() { if let navigationController = navigationController { let authorizationAssembly = assemblyFactory.authorizationAssembly() let authorizationController = authorizationAssembly.module(navigationController) navigationController.pushViewController(authorizationController, animated: true) } } }
Пробуем написать Router c Assembly
Добавим базовый класс
Пробуем написать Router с базовым классомprotocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: BaseRouter, RouterProtocol { func showAuthorization() { if let navigationController = navigationController { let authorizationAssembly = assemblyFactory.authorizationAssembly() let authorizationController = authorizationAssembly.module(navigationController) navigationController.pushViewController(authorizationController, animated: true) } } }
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: BaseRouter, RouterProtocol { func showAuthorization() { if let navigationController = navigationController { let authorizationAssembly = assemblyFactory.authorizationAssembly() let authorizationController = authorizationAssembly.module(navigationController) navigationController.pushViewController(authorizationController, animated: true) } } }
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: BaseRouter, RouterProtocol { func showAuthorization() { if let navigationController = navigationController { let authorizationAssembly = assemblyFactory.authorizationAssembly() let authorizationController = authorizationAssembly.module(navigationController) navigationController.pushViewController(authorizationController, animated: true) } } }
Вынесем в базовый класс
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: BaseRouter, RouterProtocol { func showAuthorization() { if let navigationController = navigationController { let authorizationAssembly = assemblyFactory.authorizationAssembly() let authorizationController = authorizationAssembly.module(navigationController) navigationController.pushViewController(authorizationController, animated: true) } } }
Вынесем в базовый класс
Пробуем написать Router с базовым классомprotocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: BaseRouter, RouterProtocol { func showAuthorization() { pushViewControllerDerivedFrom { navigationController -> UIViewController in let authorizationAssembly = assemblyFactory.authorizationAssembly() let authorizationController = authorizationAssembly.module(navigationController)
return authorizationController } } }
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: BaseRouter, RouterProtocol { func showAuthorization() { pushViewControllerDerivedFrom { navigationController -> UIViewController in let authorizationAssembly = assemblyFactory.authorizationAssembly() let authorizationController = authorizationAssembly.module(navigationController)
return authorizationController } } }
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: BaseRouter, RouterProtocol { func showAuthorization() { pushViewControllerDerivedFrom { navigationController -> UIViewController in let authorizationAssembly = assemblyFactory.authorizationAssembly() let authorizationController = authorizationAssembly.module(navigationController)
return authorizationController } } }
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: BaseRouter, RouterProtocol { func showAuthorization() { pushViewControllerDerivedFrom { navigationController -> UIViewController in let authorizationAssembly = assemblyFactory.authorizationAssembly() let authorizationController = authorizationAssembly.module(navigationController)
return authorizationController } } }
protocol RouterProtocol: class { func showAuthorization() }
final class RouterProtocolImpl: BaseRouter, RouterProtocol { func showAuthorization() { presentModalViewControllerDerivedFrom { navigationController -> UIViewController in let authorizationAssembly = assemblyFactory.authorizationAssembly() let authorizationController = authorizationAssembly.module(navigationController)
return authorizationController } } }
Хороший фасад
Базовый классclass BaseRouter { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? func pushViewControllerDerivedFrom(deriveViewController: UINavigationController -> UIViewController) { if let navigationController = navigationController { let viewController = deriveViewController(navigationController) navigationController.pushViewController(viewController, animated: true) } } }
class BaseRouter { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? func pushViewControllerDerivedFrom(deriveViewController: UINavigationController -> UIViewController) { if let navigationController = navigationController { let viewController = deriveViewController(navigationController) navigationController.pushViewController(viewController, animated: true) } } }
Что делать с Master-detail модулем?
Для Master-detail нужен второй навигационный контроллер
Второй базовый классclass BaseMasterDetailRouter { weak var masterNavigationController: UINavigationController? weak var detailNavigationController: UINavigationController? weak var rootViewController: UIViewController? func pushMasterViewControllerDerivedFrom(deriveViewController: UINavigationController -> UIViewController) { if let navigationController = masterNavigationController { let viewController = deriveViewController(navigationController) navigationController.pushViewController(viewController, animated: true) } } }
class BaseMasterDetailRouter { weak var masterNavigationController: UINavigationController? weak var detailNavigationController: UINavigationController? weak var rootViewController: UIViewController? func pushMasterViewControllerDerivedFrom(deriveViewController: UINavigationController -> UIViewController) { if let navigationController = masterNavigationController { let viewController = deriveViewController(navigationController) navigationController.pushViewController(viewController, animated: true) } } }
class BaseMasterDetailRouter { weak var masterNavigationController: UINavigationController? weak var detailNavigationController: UINavigationController? weak var rootViewController: UIViewController? func pushMasterViewControllerDerivedFrom(deriveViewController: UINavigationController -> UIViewController) { if let navigationController = masterNavigationController { let viewController = deriveViewController(navigationController) navigationController.pushViewController(viewController, animated: true) } } }
class BaseMasterDetailRouter { weak var masterNavigationController: UINavigationController? weak var detailNavigationController: UINavigationController? weak var rootViewController: UIViewController? func pushMasterViewControllerDerivedFrom(deriveViewController: UINavigationController -> UIViewController) { if let navigationController = masterNavigationController { let viewController = deriveViewController(navigationController) navigationController.pushViewController(viewController, animated: true) } } }
class BaseMasterDetailRouter { weak var masterNavigationController: UINavigationController? weak var detailNavigationController: UINavigationController? weak var rootViewController: UIViewController? func pushMasterViewControllerDerivedFrom(deriveViewController: UINavigationController -> UIViewController) { if let navigationController = masterNavigationController { let viewController = deriveViewController(navigationController) navigationController.pushViewController(viewController, animated: true) } } }
class BaseMasterDetailRouter { weak var masterNavigationController: UINavigationController? weak var detailNavigationController: UINavigationController? weak var rootViewController: UIViewController? func pushMasterViewControllerDerivedFrom(deriveViewController: UINavigationController -> UIViewController) { if let navigationController = masterNavigationController { let viewController = deriveViewController(navigationController) navigationController.pushViewController(viewController, animated: true) } } }
Добавим структурку для передачи
всех нужных роутерупараметров
Добавляем структуркиstruct RouterSeed { let navigationController: UINavigationController }
struct RouterSeed { let navigationController: UINavigationController }
struct MasterDetailRouterSeed { let masterNavigationController: UINavigationController let detailNavigationController: UINavigationController }
Теперь рефакторитьбудет удобней
Улучшенный фасад pushViewControllerDerivedFrom { routerSeed -> UIViewController in pushViewControllerDerivedFrom { routerSeed -> UIViewController in
pushMasterViewControllerDerivedFrom { routerSeed -> UIViewController in
pushViewControllerDerivedFrom { routerSeed -> UIViewController in
pushMasterViewControllerDerivedFrom { routerSeed -> UIViewController in
setDetailViewControllerDerivedFrom { routerSeed -> UIViewController in
pushViewControllerDerivedFrom { routerSeed -> UIViewController in
pushMasterViewControllerDerivedFrom { routerSeed -> UIViewController in
setDetailViewControllerDerivedFrom { routerSeed -> UIViewController in
presentModalNavigationControllerWithRootViewControllerDerivedFrom { routerSeed -> UIViewController in
pushViewControllerDerivedFrom { routerSeed -> UIViewController in
pushMasterViewControllerDerivedFrom { routerSeed -> UIViewController in
setDetailViewControllerDerivedFrom { routerSeed -> UIViewController in
presentModalNavigationControllerWithRootViewControllerDerivedFrom { routerSeed -> UIViewController in
presentPopoverWithNavigationControllerFromBarButtonItem(buttonItem) { routerSeed -> UIViewController in
So far, so goodМодуль авторизации из всех модулейПоддержка DeepLinksBonus: (Push’ы, Alert’ы)
Нужно научить базовые роутеры
искать верхний модуль
So far, so good, но что если
Поиск верхнего модуляprotocol TopViewControllerFinder: class { func topViewController() -> UIViewController? }
final class TopViewControllerFinderImpl: TopViewControllerFinder { weak var rootViewController: UIViewController? }
final class TopViewControllerFinderImpl: TopViewControllerFinder { weak var rootViewController: UIViewController? func topViewController() -> UIViewController? { var result = rootViewController while let presentedViewController = result?.presentedViewController { result = presentedViewController } return result } }
final class TopViewControllerFinderImpl: TopViewControllerFinder { weak var rootViewController: UIViewController? func topViewController() -> UIViewController? { var result = rootViewController while let presentedViewController = result?.presentedViewController { result = presentedViewController } return result } }
final class TopViewControllerFinderImpl: TopViewControllerFinder { weak var rootViewController: UIViewController? func topViewController() -> UIViewController? { var result = rootViewController while let presentedViewController = result?.presentedViewController { result = presentedViewController } if let selectedTabController = (result as? UITabBarController)?.selectedViewController { if let detailController = (selectedTabController as? UISplitViewController)?.viewControllers.last { if let detailNavigationController = detailController as? UINavigationController { result = detailNavigationController.viewControllers.last } else { result = detailController } } else { result = selectedTabController } } return result } }
final class TopViewControllerFinderImpl: TopViewControllerFinder { weak var rootViewController: UIViewController? func topViewController() -> UIViewController? { var result = rootViewController while let presentedViewController = result?.presentedViewController { result = presentedViewController } if let selectedTabController = (result as? UITabBarController)?.selectedViewController { if let detailController = (selectedTabController as? UISplitViewController)?.viewControllers.last { if let detailNavigationController = detailController as? UINavigationController { result = detailNavigationController.viewControllers.last } else { result = detailController } } else { result = selectedTabController } } return result } }
Нужна своя система навигации
Зачем нужна своя система навигации?Хранение истории переходов
Поддержка Third-party контроллеров
Bonus: проверка, что модуль был на экранеBonus: расстояние между модулями
Поиск верхнего модуля
Обертка над UIKit
Реакция на изменение SDK
Свежий взгляд на базовый Routerclass BaseRouter { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? }
class BaseRouter { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? }
Нужно абстрагировать Router от UIKit
Не у каждого роутера будет UINavigationController
Код вида .pushViewController() сильно завязывает Router на UIKit
Для каждого ThirdPartyNavigationController нужна будет своя пара базовых Router’ов
Абстрагируем Router от UIKit
protocol TransitionsHandler: class { }
typealias TransitionId = String Идентификатор перехода
Возвращение на модуль
Закрытие модуля
Отменяемый переходprotocol TransitionsHandler: class { func performTransition(context context: PresentationTransitionContext) }
Неотменяемый переход
protocol TransitionsHandler: class { func performTransition(context context: PresentationTransitionContext)
func resetWithTransition(context context: ResettingTransitionContext) }
protocol TransitionsHandler: class { func performTransition(context context: PresentationTransitionContext)
func resetWithTransition(context context: ResettingTransitionContext)
func undoTransitionsAfter(transitionId transitionId: TransitionId) }
protocol TransitionsHandler: class { func performTransition(context context: PresentationTransitionContext)
func resetWithTransition(context context: ResettingTransitionContext)
func undoTransitionsAfter(transitionId transitionId: TransitionId)
func undoTransitionWith(transitionId transitionId: TransitionId) }
Router общается с
обработчиком переходов
Обработчик переходов оборачивает UIViewController
Виды модулей Анимирующие
AnimatingTransitionsHandlerImpl
NavigationTransitionsHandlerImpl
ContainerTransitionsHandlerImpl
SplitViewTransitionsHandlerImpl
TabBarTransitionsHandlerImpl
Контейнеры
pushViewController(_:animated:)presentViewController(_:animated:completion:)
visibleAnimatingTransitionsHandlers()allAnimatingTransitionsHandlers()
Легко добавить Third-party контроллер
class BaseRouter { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? }
Новый базовый Routerclass BaseRouter { let transitionsHandlerBox: TransitionsHandlerBox // weak var navigationController: UINavigationController? let transitionId: TransitionId // weak var rootViewController: UIViewController? }
class BaseRouter { let transitionsHandlerBox: TransitionsHandlerBox // weak var navigationController: UINavigationController? let transitionId: TransitionId // weak var rootViewController: UIViewController? }
class BaseRouter { let transitionsHandlerBox: TransitionsHandlerBox // weak var navigationController: UINavigationController? let transitionId: TransitionId // weak var rootViewController: UIViewController? }
class BaseRouter { let transitionsHandlerBox: TransitionsHandlerBox // weak var navigationController: UINavigationController? let transitionId: TransitionId // weak var rootViewController: UIViewController? }
enum TransitionsHandlerBox { case Animating(AnimatingTransitionsHandlerImpl) case Containing(ContainingTransitionsHandlerImpl) }
Такой Router можно использовать
с любым UIViewController’ом
Схема выполнения отменяемых переходов
Transitions handlerbox
выполни отменяемый переход
Router
presentation context
transitions handler
box Transitions Coordinator
Top animating transitions handler запусти
анимацию
presentation context
Взглянем еще раз на новый базовый Routerclass BaseRouter { let transitionsHandlerBox: TransitionsHandlerBox // weak var navigationController: UINavigationController? let transitionId: TransitionId // weak var rootViewController: UIViewController? }
Нужна ссылка на обработчика переходов, показавшего модуль Router’а
class BaseRouter { let transitionsHandlerBox: TransitionsHandlerBox // weak var navigationController: UINavigationController? let transitionId: TransitionId // weak var rootViewController: UIViewController? weak var presentingTransitionsHandler: TransitionsHandler? }
class BaseRouter { let transitionsHandlerBox: TransitionsHandlerBox // weak var navigationController: UINavigationController? let transitionId: TransitionId // weak var rootViewController: UIViewController? weak var presentingTransitionsHandler: TransitionsHandler? }
Теперь роутер может закрывать свой модуль
Навигационная связь
Router 1
transition id 1
Transitions handler 1
Transitions handler 2
presenting transitions
handler
Вернись на модуль 1
Закрой модуль 2
Router 2
transition id 2
Что лучше: “Вернись на модуль 1”
или “Закрой модуль 2”
?
Flow
Фильтр Города
Выход из Flow
Фильтр Города
Router
dismiss cities
Усложненный flow
Фильтр Регионы Города
Выход из Flow
Фильтрmodule output
ГородаРегионыmodule output
Router
return to filter
“Вернись на модуль” гибче, чем
“Закрой модуль”
Слой Router
Предварительные итоги
Подходы к выполнению обратных переходовПоддержка DeepLinks
Слой AssemblyБазовые классы Router, поддержка iPad, master-detailПростой Router (фасад, абстрация от UIKit, поддержка Third-Party)
demo.start()
Один UIViewController, много Router’ов
Выводы по демо
Проверка наличия модуля в истории (Авторизация)
Проверка isIpad()Поиск верхнего модуля (Авторизация, DeepLink’и, Push’ы)
Проверка модулей на дубликаты (🍌, 🍏)Аниматоры переходов
Проверка isIpad()
Выделите слой Router (определять стиль перехода)
Общие советы
Используйте “Вернись на модуль” вместо “Закрой модуль”
Выделите слой Assembly (верьте в появление DI для Swift)Абстрагируйте Router от UIKit
Вынесите логику принятия решений в отдельный слойОписывайте переходы в декларативном стиле
One more thing
https://github.com/avito-tech/Marshroute
Исходники Докладчик: Юсипов Тимурhttps://vk.com/ma3tsa
fizmatchelskype
personal mail
work mail
vk
Marshroute
Спасибо за внимание!
presentation.finish()
https://github.com/avito-tech/Marshroute/tree/master/Example
Демо