SlideShare ist ein Scribd-Unternehmen logo
1 von 35
Downloaden Sie, um offline zu lesen
Удобный и расширяемый
роутинг в 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()
}
Пробуем написать Router
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)
}
}
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
Добавляем слой Assembly
protocol 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 Assembly
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() {
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 inpushViewControllerDerivedFrom { 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
Модуль авторизации из всех модулей
Поддержка DeepLinks
Bonus: (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
Свежий взгляд на базовый Router
class 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?
}
Новый базовый Router
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?
}
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 handler
box
выполни
отменяемый
переход
Router
presentation
context
transitions
handler
box Transitions
Coordinator
Top animating
transitions handlerзапусти
анимацию
presentation
context
Взглянем еще раз на новый базовый Router
class 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
tyusipov@avito.ru
ykylele@gmail.com
fizmatchelskype
personal mail
work mail
vk
Marshroute
Спасибо за внимание!
presentation.finish()
https://github.com/avito-tech/Marshroute/tree/master/Example
Демо

Weitere ähnliche Inhalte

Andere mochten auch

"Опыт использования Sphinx в Ozon.ru" Игорь Чакрыгин (OZON.RU)
"Опыт использования Sphinx в Ozon.ru" Игорь Чакрыгин (OZON.RU)"Опыт использования Sphinx в Ozon.ru" Игорь Чакрыгин (OZON.RU)
"Опыт использования Sphinx в Ozon.ru" Игорь Чакрыгин (OZON.RU)AvitoTech
 
"Подходы, используемые в разработке iOS-клиента Viber" Кирилл Лашкевич (Viber)
"Подходы, используемые в разработке iOS-клиента Viber" Кирилл Лашкевич (Viber)"Подходы, используемые в разработке iOS-клиента Viber" Кирилл Лашкевич (Viber)
"Подходы, используемые в разработке iOS-клиента Viber" Кирилл Лашкевич (Viber)AvitoTech
 
"Ускорение сборки большого проекта на Objective-C + Swift" Иван Бондарь (Avito)
"Ускорение сборки большого проекта на Objective-C + Swift" Иван Бондарь (Avito)"Ускорение сборки большого проекта на Objective-C + Swift" Иван Бондарь (Avito)
"Ускорение сборки большого проекта на Objective-C + Swift" Иван Бондарь (Avito)AvitoTech
 
"Kotlin и rx в android" Дмитрий Воронин (Avito)
"Kotlin и rx в android" Дмитрий Воронин  (Avito)"Kotlin и rx в android" Дмитрий Воронин  (Avito)
"Kotlin и rx в android" Дмитрий Воронин (Avito)AvitoTech
 
"Basis.js - Production Ready SPA Framework" Сергей Мелюков (Avito)
"Basis.js - Production Ready SPA Framework" Сергей Мелюков (Avito)"Basis.js - Production Ready SPA Framework" Сергей Мелюков (Avito)
"Basis.js - Production Ready SPA Framework" Сергей Мелюков (Avito)AvitoTech
 
"Опыт участия в Microsoft Malware Classification Challenge" Михаил Трофимов ...
"Опыт участия в Microsoft Malware Classification Challenge"  Михаил Трофимов ..."Опыт участия в Microsoft Malware Classification Challenge"  Михаил Трофимов ...
"Опыт участия в Microsoft Malware Classification Challenge" Михаил Трофимов ...AvitoTech
 
"Быстрое внедрение Sphinx на примере проекта Фоксфорд.Учебник" Антон Ковалёв ...
"Быстрое внедрение Sphinx на примере проекта Фоксфорд.Учебник" Антон Ковалёв ..."Быстрое внедрение Sphinx на примере проекта Фоксфорд.Учебник" Антон Ковалёв ...
"Быстрое внедрение Sphinx на примере проекта Фоксфорд.Учебник" Антон Ковалёв ...AvitoTech
 
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)Ontico
 
“Атличнаи дивчачьи каньки”: исправляем ошибки. Андрей Смирнов (Avito)
“Атличнаи дивчачьи каньки”: исправляем ошибки. Андрей Смирнов (Avito)“Атличнаи дивчачьи каньки”: исправляем ошибки. Андрей Смирнов (Avito)
“Атличнаи дивчачьи каньки”: исправляем ошибки. Андрей Смирнов (Avito)AvitoTech
 
"DeepLink’и в Avito" Артём Разинов (Avito)
"DeepLink’и в Avito" Артём Разинов (Avito)"DeepLink’и в Avito" Артём Разинов (Avito)
"DeepLink’и в Avito" Артём Разинов (Avito)AvitoTech
 
"REST-SOA-View-Controller или Проектирование сервис-ориентированной системы с...
"REST-SOA-View-Controller или Проектирование сервис-ориентированной системы с..."REST-SOA-View-Controller или Проектирование сервис-ориентированной системы с...
"REST-SOA-View-Controller или Проектирование сервис-ориентированной системы с...AvitoTech
 
"Секционирование без границ" Ильдар Мусин (Postgres Professional)
"Секционирование без границ" Ильдар Мусин (Postgres Professional)"Секционирование без границ" Ильдар Мусин (Postgres Professional)
"Секционирование без границ" Ильдар Мусин (Postgres Professional)AvitoTech
 
"Распознавание марки и модели автомашин на изображениях" Евгений Нижибицкий (...
"Распознавание марки и модели автомашин на изображениях" Евгений Нижибицкий (..."Распознавание марки и модели автомашин на изображениях" Евгений Нижибицкий (...
"Распознавание марки и модели автомашин на изображениях" Евгений Нижибицкий (...AvitoTech
 
"Распознавание категории объявления по изображениям" Артур Кузин (МФТИ)
"Распознавание категории объявления по изображениям" Артур Кузин (МФТИ)"Распознавание категории объявления по изображениям" Артур Кузин (МФТИ)
"Распознавание категории объявления по изображениям" Артур Кузин (МФТИ)AvitoTech
 
noBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов Николай
noBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов НиколайnoBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов Николай
noBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов НиколайOntico
 
"Погружение в Robolectric" Дмитрий Костырев (Avito)
"Погружение в Robolectric"  Дмитрий Костырев (Avito)"Погружение в Robolectric"  Дмитрий Костырев (Avito)
"Погружение в Robolectric" Дмитрий Костырев (Avito)AvitoTech
 
"Успеть за 100 миллисекунд: контекстная реклама на Sphinx" Дмитрий Хасанов (...
"Успеть за 100 миллисекунд: контекстная реклама на Sphinx" Дмитрий Хасанов  (..."Успеть за 100 миллисекунд: контекстная реклама на Sphinx" Дмитрий Хасанов  (...
"Успеть за 100 миллисекунд: контекстная реклама на Sphinx" Дмитрий Хасанов (...AvitoTech
 
"Kotlin для Android: 1.0 и далее" Дмитрий Жемеров (JetBrains)
"Kotlin для Android: 1.0 и далее" Дмитрий Жемеров (JetBrains)"Kotlin для Android: 1.0 и далее" Дмитрий Жемеров (JetBrains)
"Kotlin для Android: 1.0 и далее" Дмитрий Жемеров (JetBrains)AvitoTech
 
"Построение рекомендательной системы на Python" Василий Лексин (Avito)
"Построение рекомендательной системы на Python" Василий Лексин (Avito)"Построение рекомендательной системы на Python" Василий Лексин (Avito)
"Построение рекомендательной системы на Python" Василий Лексин (Avito)AvitoTech
 
"Контекстная реклама в Avito: что под капотом?" Вадим Аюев и Андрей Остапец (...
"Контекстная реклама в Avito: что под капотом?" Вадим Аюев и Андрей Остапец (..."Контекстная реклама в Avito: что под капотом?" Вадим Аюев и Андрей Остапец (...
"Контекстная реклама в Avito: что под капотом?" Вадим Аюев и Андрей Остапец (...AvitoTech
 

Andere mochten auch (20)

"Опыт использования Sphinx в Ozon.ru" Игорь Чакрыгин (OZON.RU)
"Опыт использования Sphinx в Ozon.ru" Игорь Чакрыгин (OZON.RU)"Опыт использования Sphinx в Ozon.ru" Игорь Чакрыгин (OZON.RU)
"Опыт использования Sphinx в Ozon.ru" Игорь Чакрыгин (OZON.RU)
 
"Подходы, используемые в разработке iOS-клиента Viber" Кирилл Лашкевич (Viber)
"Подходы, используемые в разработке iOS-клиента Viber" Кирилл Лашкевич (Viber)"Подходы, используемые в разработке iOS-клиента Viber" Кирилл Лашкевич (Viber)
"Подходы, используемые в разработке iOS-клиента Viber" Кирилл Лашкевич (Viber)
 
"Ускорение сборки большого проекта на Objective-C + Swift" Иван Бондарь (Avito)
"Ускорение сборки большого проекта на Objective-C + Swift" Иван Бондарь (Avito)"Ускорение сборки большого проекта на Objective-C + Swift" Иван Бондарь (Avito)
"Ускорение сборки большого проекта на Objective-C + Swift" Иван Бондарь (Avito)
 
"Kotlin и rx в android" Дмитрий Воронин (Avito)
"Kotlin и rx в android" Дмитрий Воронин  (Avito)"Kotlin и rx в android" Дмитрий Воронин  (Avito)
"Kotlin и rx в android" Дмитрий Воронин (Avito)
 
"Basis.js - Production Ready SPA Framework" Сергей Мелюков (Avito)
"Basis.js - Production Ready SPA Framework" Сергей Мелюков (Avito)"Basis.js - Production Ready SPA Framework" Сергей Мелюков (Avito)
"Basis.js - Production Ready SPA Framework" Сергей Мелюков (Avito)
 
"Опыт участия в Microsoft Malware Classification Challenge" Михаил Трофимов ...
"Опыт участия в Microsoft Malware Classification Challenge"  Михаил Трофимов ..."Опыт участия в Microsoft Malware Classification Challenge"  Михаил Трофимов ...
"Опыт участия в Microsoft Malware Classification Challenge" Михаил Трофимов ...
 
"Быстрое внедрение Sphinx на примере проекта Фоксфорд.Учебник" Антон Ковалёв ...
"Быстрое внедрение Sphinx на примере проекта Фоксфорд.Учебник" Антон Ковалёв ..."Быстрое внедрение Sphinx на примере проекта Фоксфорд.Учебник" Антон Ковалёв ...
"Быстрое внедрение Sphinx на примере проекта Фоксфорд.Учебник" Антон Ковалёв ...
 
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
 
“Атличнаи дивчачьи каньки”: исправляем ошибки. Андрей Смирнов (Avito)
“Атличнаи дивчачьи каньки”: исправляем ошибки. Андрей Смирнов (Avito)“Атличнаи дивчачьи каньки”: исправляем ошибки. Андрей Смирнов (Avito)
“Атличнаи дивчачьи каньки”: исправляем ошибки. Андрей Смирнов (Avito)
 
"DeepLink’и в Avito" Артём Разинов (Avito)
"DeepLink’и в Avito" Артём Разинов (Avito)"DeepLink’и в Avito" Артём Разинов (Avito)
"DeepLink’и в Avito" Артём Разинов (Avito)
 
"REST-SOA-View-Controller или Проектирование сервис-ориентированной системы с...
"REST-SOA-View-Controller или Проектирование сервис-ориентированной системы с..."REST-SOA-View-Controller или Проектирование сервис-ориентированной системы с...
"REST-SOA-View-Controller или Проектирование сервис-ориентированной системы с...
 
"Секционирование без границ" Ильдар Мусин (Postgres Professional)
"Секционирование без границ" Ильдар Мусин (Postgres Professional)"Секционирование без границ" Ильдар Мусин (Postgres Professional)
"Секционирование без границ" Ильдар Мусин (Postgres Professional)
 
"Распознавание марки и модели автомашин на изображениях" Евгений Нижибицкий (...
"Распознавание марки и модели автомашин на изображениях" Евгений Нижибицкий (..."Распознавание марки и модели автомашин на изображениях" Евгений Нижибицкий (...
"Распознавание марки и модели автомашин на изображениях" Евгений Нижибицкий (...
 
"Распознавание категории объявления по изображениям" Артур Кузин (МФТИ)
"Распознавание категории объявления по изображениям" Артур Кузин (МФТИ)"Распознавание категории объявления по изображениям" Артур Кузин (МФТИ)
"Распознавание категории объявления по изображениям" Артур Кузин (МФТИ)
 
noBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов Николай
noBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов НиколайnoBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов Николай
noBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов Николай
 
"Погружение в Robolectric" Дмитрий Костырев (Avito)
"Погружение в Robolectric"  Дмитрий Костырев (Avito)"Погружение в Robolectric"  Дмитрий Костырев (Avito)
"Погружение в Robolectric" Дмитрий Костырев (Avito)
 
"Успеть за 100 миллисекунд: контекстная реклама на Sphinx" Дмитрий Хасанов (...
"Успеть за 100 миллисекунд: контекстная реклама на Sphinx" Дмитрий Хасанов  (..."Успеть за 100 миллисекунд: контекстная реклама на Sphinx" Дмитрий Хасанов  (...
"Успеть за 100 миллисекунд: контекстная реклама на Sphinx" Дмитрий Хасанов (...
 
"Kotlin для Android: 1.0 и далее" Дмитрий Жемеров (JetBrains)
"Kotlin для Android: 1.0 и далее" Дмитрий Жемеров (JetBrains)"Kotlin для Android: 1.0 и далее" Дмитрий Жемеров (JetBrains)
"Kotlin для Android: 1.0 и далее" Дмитрий Жемеров (JetBrains)
 
"Построение рекомендательной системы на Python" Василий Лексин (Avito)
"Построение рекомендательной системы на Python" Василий Лексин (Avito)"Построение рекомендательной системы на Python" Василий Лексин (Avito)
"Построение рекомендательной системы на Python" Василий Лексин (Avito)
 
"Контекстная реклама в Avito: что под капотом?" Вадим Аюев и Андрей Остапец (...
"Контекстная реклама в Avito: что под капотом?" Вадим Аюев и Андрей Остапец (..."Контекстная реклама в Avito: что под капотом?" Вадим Аюев и Андрей Остапец (...
"Контекстная реклама в Avito: что под капотом?" Вадим Аюев и Андрей Остапец (...
 

Ähnlich wie "Удобный и расширяемый роутинг в iOS-приложении" Тимур Юсипов (Avito)

What's new in Android P @ I/O Extended Bangkok 2018
What's new in Android P @ I/O Extended Bangkok 2018What's new in Android P @ I/O Extended Bangkok 2018
What's new in Android P @ I/O Extended Bangkok 2018Somkiat Khitwongwattana
 
Developing ASP.NET Applications Using the Model View Controller Pattern
Developing ASP.NET Applications Using the Model View Controller PatternDeveloping ASP.NET Applications Using the Model View Controller Pattern
Developing ASP.NET Applications Using the Model View Controller Patterngoodfriday
 
Workshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte IIWorkshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte IIVisual Engineering
 
Angular js routing options
Angular js routing optionsAngular js routing options
Angular js routing optionsNir Kaufman
 
Do iOS Presentation - Mobile app architectures
Do iOS Presentation - Mobile app architecturesDo iOS Presentation - Mobile app architectures
Do iOS Presentation - Mobile app architecturesDavid Broža
 
The Next Step in AS3 Framework Evolution - FITC Amsterdam 2013
The Next Step in AS3 Framework Evolution - FITC Amsterdam 2013The Next Step in AS3 Framework Evolution - FITC Amsterdam 2013
The Next Step in AS3 Framework Evolution - FITC Amsterdam 2013Raimundas Banevičius
 
How to instantiate any view controller for free
How to instantiate any view controller for freeHow to instantiate any view controller for free
How to instantiate any view controller for freeBenotCaron
 
Foomo / Zugspitze Presentation
Foomo / Zugspitze PresentationFoomo / Zugspitze Presentation
Foomo / Zugspitze Presentationweareinteractive
 
알아보자 Dependency Injection과 Deli
알아보자 Dependency Injection과 Deli알아보자 Dependency Injection과 Deli
알아보자 Dependency Injection과 DeliJungwon An
 
MBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&CoMBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&Coe-Legion
 
Practical Protocol-Oriented-Programming
Practical Protocol-Oriented-ProgrammingPractical Protocol-Oriented-Programming
Practical Protocol-Oriented-ProgrammingNatasha Murashev
 
Practialpop 160510130818
Practialpop 160510130818Practialpop 160510130818
Practialpop 160510130818Shahzain Saeed
 
MCE^3 - Natasha Murashev - Practical Protocol-Oriented Programming in Swift
MCE^3 - Natasha Murashev - Practical Protocol-Oriented Programming in SwiftMCE^3 - Natasha Murashev - Practical Protocol-Oriented Programming in Swift
MCE^3 - Natasha Murashev - Practical Protocol-Oriented Programming in SwiftPROIDEA
 
[22]Efficient and Testable MVVM pattern
[22]Efficient and Testable MVVM pattern[22]Efficient and Testable MVVM pattern
[22]Efficient and Testable MVVM patternNAVER Engineering
 
Daggerate your code - Write your own annotation processor
Daggerate your code - Write your own annotation processorDaggerate your code - Write your own annotation processor
Daggerate your code - Write your own annotation processorBartosz Kosarzycki
 
Migrating Objective-C to Swift
Migrating Objective-C to SwiftMigrating Objective-C to Swift
Migrating Objective-C to SwiftElmar Kretzer
 
ITT 2014 - Peter Steinberger - Architecting Modular Codebases
ITT 2014 - Peter Steinberger - Architecting Modular CodebasesITT 2014 - Peter Steinberger - Architecting Modular Codebases
ITT 2014 - Peter Steinberger - Architecting Modular CodebasesIstanbul Tech Talks
 
The Next Step in AS3 Framework Evolution
The Next Step in AS3 Framework EvolutionThe Next Step in AS3 Framework Evolution
The Next Step in AS3 Framework EvolutionFITC
 
Inversion Of Control
Inversion Of ControlInversion Of Control
Inversion Of ControlChad Hietala
 

Ähnlich wie "Удобный и расширяемый роутинг в iOS-приложении" Тимур Юсипов (Avito) (20)

What's new in Android P @ I/O Extended Bangkok 2018
What's new in Android P @ I/O Extended Bangkok 2018What's new in Android P @ I/O Extended Bangkok 2018
What's new in Android P @ I/O Extended Bangkok 2018
 
Developing ASP.NET Applications Using the Model View Controller Pattern
Developing ASP.NET Applications Using the Model View Controller PatternDeveloping ASP.NET Applications Using the Model View Controller Pattern
Developing ASP.NET Applications Using the Model View Controller Pattern
 
Workshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte IIWorkshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte II
 
Angular js routing options
Angular js routing optionsAngular js routing options
Angular js routing options
 
Do iOS Presentation - Mobile app architectures
Do iOS Presentation - Mobile app architecturesDo iOS Presentation - Mobile app architectures
Do iOS Presentation - Mobile app architectures
 
The Next Step in AS3 Framework Evolution - FITC Amsterdam 2013
The Next Step in AS3 Framework Evolution - FITC Amsterdam 2013The Next Step in AS3 Framework Evolution - FITC Amsterdam 2013
The Next Step in AS3 Framework Evolution - FITC Amsterdam 2013
 
Exemplo de Fluxograma de Arquitetura aplicativo
Exemplo de Fluxograma de Arquitetura aplicativoExemplo de Fluxograma de Arquitetura aplicativo
Exemplo de Fluxograma de Arquitetura aplicativo
 
How to instantiate any view controller for free
How to instantiate any view controller for freeHow to instantiate any view controller for free
How to instantiate any view controller for free
 
Foomo / Zugspitze Presentation
Foomo / Zugspitze PresentationFoomo / Zugspitze Presentation
Foomo / Zugspitze Presentation
 
알아보자 Dependency Injection과 Deli
알아보자 Dependency Injection과 Deli알아보자 Dependency Injection과 Deli
알아보자 Dependency Injection과 Deli
 
MBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&CoMBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&Co
 
Practical Protocol-Oriented-Programming
Practical Protocol-Oriented-ProgrammingPractical Protocol-Oriented-Programming
Practical Protocol-Oriented-Programming
 
Practialpop 160510130818
Practialpop 160510130818Practialpop 160510130818
Practialpop 160510130818
 
MCE^3 - Natasha Murashev - Practical Protocol-Oriented Programming in Swift
MCE^3 - Natasha Murashev - Practical Protocol-Oriented Programming in SwiftMCE^3 - Natasha Murashev - Practical Protocol-Oriented Programming in Swift
MCE^3 - Natasha Murashev - Practical Protocol-Oriented Programming in Swift
 
[22]Efficient and Testable MVVM pattern
[22]Efficient and Testable MVVM pattern[22]Efficient and Testable MVVM pattern
[22]Efficient and Testable MVVM pattern
 
Daggerate your code - Write your own annotation processor
Daggerate your code - Write your own annotation processorDaggerate your code - Write your own annotation processor
Daggerate your code - Write your own annotation processor
 
Migrating Objective-C to Swift
Migrating Objective-C to SwiftMigrating Objective-C to Swift
Migrating Objective-C to Swift
 
ITT 2014 - Peter Steinberger - Architecting Modular Codebases
ITT 2014 - Peter Steinberger - Architecting Modular CodebasesITT 2014 - Peter Steinberger - Architecting Modular Codebases
ITT 2014 - Peter Steinberger - Architecting Modular Codebases
 
The Next Step in AS3 Framework Evolution
The Next Step in AS3 Framework EvolutionThe Next Step in AS3 Framework Evolution
The Next Step in AS3 Framework Evolution
 
Inversion Of Control
Inversion Of ControlInversion Of Control
Inversion Of Control
 

Mehr von AvitoTech

Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)
Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)
Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)AvitoTech
 
Применение компьютерного зрения для анализа спортивных соревнований (Николай ...
Применение компьютерного зрения для анализа спортивных соревнований (Николай ...Применение компьютерного зрения для анализа спортивных соревнований (Николай ...
Применение компьютерного зрения для анализа спортивных соревнований (Николай ...AvitoTech
 
Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)
Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)
Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)AvitoTech
 
AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)
AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)
AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)AvitoTech
 
Yandex Tank - Арсений Фомченко
Yandex Tank - Арсений ФомченкоYandex Tank - Арсений Фомченко
Yandex Tank - Арсений ФомченкоAvitoTech
 
Migro - Юрий Богомолов
Migro - Юрий БогомоловMigro - Юрий Богомолов
Migro - Юрий БогомоловAvitoTech
 
TableKit - Максим Соколов
TableKit - Максим СоколовTableKit - Максим Соколов
TableKit - Максим СоколовAvitoTech
 
Jsonwire Grid - Михаил Подцерковский (Avito)
Jsonwire Grid - Михаил Подцерковский (Avito)Jsonwire Grid - Михаил Подцерковский (Avito)
Jsonwire Grid - Михаил Подцерковский (Avito)AvitoTech
 
SimplePEG - Алексей Охрименко
SimplePEG - Алексей ОхрименкоSimplePEG - Алексей Охрименко
SimplePEG - Алексей ОхрименкоAvitoTech
 
Как перестать бояться и начать контрибьютить - Алексей Кудрявцев
 Как перестать бояться и начать контрибьютить - Алексей Кудрявцев Как перестать бояться и начать контрибьютить - Алексей Кудрявцев
Как перестать бояться и начать контрибьютить - Алексей КудрявцевAvitoTech
 
"Анонимизация фото с помощью Vision", Хомутников Тимофей, Avito
"Анонимизация фото с помощью Vision",  Хомутников Тимофей, Avito"Анонимизация фото с помощью Vision",  Хомутников Тимофей, Avito
"Анонимизация фото с помощью Vision", Хомутников Тимофей, AvitoAvitoTech
 
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
“iOS 11 в App in the Air”, Пронин Сергей, App in the AirAvitoTech
 
"ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb...
"ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb..."ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb...
"ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb...AvitoTech
 
ASO for iOS 11
ASO for iOS 11ASO for iOS 11
ASO for iOS 11AvitoTech
 
Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)
Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)
Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)AvitoTech
 
Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...
Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...
Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...AvitoTech
 
Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)
Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)
Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)AvitoTech
 
Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)
Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)
Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)AvitoTech
 
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...AvitoTech
 
Конкурс Авито-2017 - Решение 2ое место - Василий Рубцов
Конкурс Авито-2017 - Решение 2ое место - Василий РубцовКонкурс Авито-2017 - Решение 2ое место - Василий Рубцов
Конкурс Авито-2017 - Решение 2ое место - Василий РубцовAvitoTech
 

Mehr von AvitoTech (20)

Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)
Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)
Сегментация изображений на острие науки (Евгений Нижибицкий, Rambler&Co)
 
Применение компьютерного зрения для анализа спортивных соревнований (Николай ...
Применение компьютерного зрения для анализа спортивных соревнований (Николай ...Применение компьютерного зрения для анализа спортивных соревнований (Николай ...
Применение компьютерного зрения для анализа спортивных соревнований (Николай ...
 
Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)
Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)
Распознавание лиц с помощью глубоких нейронных сетей (Сергей Миляев, VisionLabs)
 
AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)
AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)
AvitoNet: сервис компьютерного зрения в Avito (Артур Кузин, Avito)
 
Yandex Tank - Арсений Фомченко
Yandex Tank - Арсений ФомченкоYandex Tank - Арсений Фомченко
Yandex Tank - Арсений Фомченко
 
Migro - Юрий Богомолов
Migro - Юрий БогомоловMigro - Юрий Богомолов
Migro - Юрий Богомолов
 
TableKit - Максим Соколов
TableKit - Максим СоколовTableKit - Максим Соколов
TableKit - Максим Соколов
 
Jsonwire Grid - Михаил Подцерковский (Avito)
Jsonwire Grid - Михаил Подцерковский (Avito)Jsonwire Grid - Михаил Подцерковский (Avito)
Jsonwire Grid - Михаил Подцерковский (Avito)
 
SimplePEG - Алексей Охрименко
SimplePEG - Алексей ОхрименкоSimplePEG - Алексей Охрименко
SimplePEG - Алексей Охрименко
 
Как перестать бояться и начать контрибьютить - Алексей Кудрявцев
 Как перестать бояться и начать контрибьютить - Алексей Кудрявцев Как перестать бояться и начать контрибьютить - Алексей Кудрявцев
Как перестать бояться и начать контрибьютить - Алексей Кудрявцев
 
"Анонимизация фото с помощью Vision", Хомутников Тимофей, Avito
"Анонимизация фото с помощью Vision",  Хомутников Тимофей, Avito"Анонимизация фото с помощью Vision",  Хомутников Тимофей, Avito
"Анонимизация фото с помощью Vision", Хомутников Тимофей, Avito
 
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
 
"ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb...
"ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb..."ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb...
"ARKit в приложении Афиша Рестораны”, Меджлумян Самвел, Антышев Дмитрий, Ramb...
 
ASO for iOS 11
ASO for iOS 11ASO for iOS 11
ASO for iOS 11
 
Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)
Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)
Добиваемся эффективности каждого из 9000+ UI-тестов - Максим Сахаров (Tutu.ru)
 
Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...
Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...
Проблемы управления тестами, или Что мешает создавать дешевые и полезные тест...
 
Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)
Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)
Запускаем тесты в Continuous Integration - Сергей Пак (JetBrains)
 
Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)
Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)
Векторы развития систем автоматизации тестирования - Дмитрий Химион (Avito)
 
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
 
Конкурс Авито-2017 - Решение 2ое место - Василий Рубцов
Конкурс Авито-2017 - Решение 2ое место - Василий РубцовКонкурс Авито-2017 - Решение 2ое место - Василий Рубцов
Конкурс Авито-2017 - Решение 2ое место - Василий Рубцов
 

Kürzlich hochgeladen

Best VIP Call Girls Noida Sector 75 Call Me: 8448380779
Best VIP Call Girls Noida Sector 75 Call Me: 8448380779Best VIP Call Girls Noida Sector 75 Call Me: 8448380779
Best VIP Call Girls Noida Sector 75 Call Me: 8448380779Delhi Call girls
 
AWS Community DAY Albertini-Ellan Cloud Security (1).pptx
AWS Community DAY Albertini-Ellan Cloud Security (1).pptxAWS Community DAY Albertini-Ellan Cloud Security (1).pptx
AWS Community DAY Albertini-Ellan Cloud Security (1).pptxellan12
 
(+971568250507 ))# Young Call Girls in Ajman By Pakistani Call Girls in ...
(+971568250507  ))#  Young Call Girls  in Ajman  By Pakistani Call Girls  in ...(+971568250507  ))#  Young Call Girls  in Ajman  By Pakistani Call Girls  in ...
(+971568250507 ))# Young Call Girls in Ajman By Pakistani Call Girls in ...Escorts Call Girls
 
Moving Beyond Twitter/X and Facebook - Social Media for local news providers
Moving Beyond Twitter/X and Facebook - Social Media for local news providersMoving Beyond Twitter/X and Facebook - Social Media for local news providers
Moving Beyond Twitter/X and Facebook - Social Media for local news providersDamian Radcliffe
 
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663Call Girls Mumbai
 
VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting High Prof...
VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting  High Prof...VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting  High Prof...
VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting High Prof...singhpriety023
 
Call Girls In Pratap Nagar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Pratap Nagar Delhi 💯Call Us 🔝8264348440🔝Call Girls In Pratap Nagar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Pratap Nagar Delhi 💯Call Us 🔝8264348440🔝soniya singh
 
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.soniya singh
 
₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...
₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...
₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...Diya Sharma
 
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...APNIC
 
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip CallDelhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Callshivangimorya083
 
On Starlink, presented by Geoff Huston at NZNOG 2024
On Starlink, presented by Geoff Huston at NZNOG 2024On Starlink, presented by Geoff Huston at NZNOG 2024
On Starlink, presented by Geoff Huston at NZNOG 2024APNIC
 
Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...
Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...
Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...SofiyaSharma5
 
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night StandHot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Standkumarajju5765
 
Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝soniya singh
 
Call Girls Service Chandigarh Lucky ❤️ 7710465962 Independent Call Girls In C...
Call Girls Service Chandigarh Lucky ❤️ 7710465962 Independent Call Girls In C...Call Girls Service Chandigarh Lucky ❤️ 7710465962 Independent Call Girls In C...
Call Girls Service Chandigarh Lucky ❤️ 7710465962 Independent Call Girls In C...Sheetaleventcompany
 

Kürzlich hochgeladen (20)

Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...
Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...
Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...
 
Best VIP Call Girls Noida Sector 75 Call Me: 8448380779
Best VIP Call Girls Noida Sector 75 Call Me: 8448380779Best VIP Call Girls Noida Sector 75 Call Me: 8448380779
Best VIP Call Girls Noida Sector 75 Call Me: 8448380779
 
AWS Community DAY Albertini-Ellan Cloud Security (1).pptx
AWS Community DAY Albertini-Ellan Cloud Security (1).pptxAWS Community DAY Albertini-Ellan Cloud Security (1).pptx
AWS Community DAY Albertini-Ellan Cloud Security (1).pptx
 
(+971568250507 ))# Young Call Girls in Ajman By Pakistani Call Girls in ...
(+971568250507  ))#  Young Call Girls  in Ajman  By Pakistani Call Girls  in ...(+971568250507  ))#  Young Call Girls  in Ajman  By Pakistani Call Girls  in ...
(+971568250507 ))# Young Call Girls in Ajman By Pakistani Call Girls in ...
 
Moving Beyond Twitter/X and Facebook - Social Media for local news providers
Moving Beyond Twitter/X and Facebook - Social Media for local news providersMoving Beyond Twitter/X and Facebook - Social Media for local news providers
Moving Beyond Twitter/X and Facebook - Social Media for local news providers
 
(INDIRA) Call Girl Pune Call Now 8250077686 Pune Escorts 24x7
(INDIRA) Call Girl Pune Call Now 8250077686 Pune Escorts 24x7(INDIRA) Call Girl Pune Call Now 8250077686 Pune Escorts 24x7
(INDIRA) Call Girl Pune Call Now 8250077686 Pune Escorts 24x7
 
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663
 
VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting High Prof...
VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting  High Prof...VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting  High Prof...
VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting High Prof...
 
Call Girls In Pratap Nagar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Pratap Nagar Delhi 💯Call Us 🔝8264348440🔝Call Girls In Pratap Nagar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Pratap Nagar Delhi 💯Call Us 🔝8264348440🔝
 
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
 
₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...
₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...
₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...
 
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...
 
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip CallDelhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
 
On Starlink, presented by Geoff Huston at NZNOG 2024
On Starlink, presented by Geoff Huston at NZNOG 2024On Starlink, presented by Geoff Huston at NZNOG 2024
On Starlink, presented by Geoff Huston at NZNOG 2024
 
Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...
Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...
Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...
 
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night StandHot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
 
Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝
 
Rohini Sector 26 Call Girls Delhi 9999965857 @Sabina Saikh No Advance
Rohini Sector 26 Call Girls Delhi 9999965857 @Sabina Saikh No AdvanceRohini Sector 26 Call Girls Delhi 9999965857 @Sabina Saikh No Advance
Rohini Sector 26 Call Girls Delhi 9999965857 @Sabina Saikh No Advance
 
Call Girls Service Chandigarh Lucky ❤️ 7710465962 Independent Call Girls In C...
Call Girls Service Chandigarh Lucky ❤️ 7710465962 Independent Call Girls In C...Call Girls Service Chandigarh Lucky ❤️ 7710465962 Independent Call Girls In C...
Call Girls Service Chandigarh Lucky ❤️ 7710465962 Independent Call Girls In C...
 
VVVIP Call Girls In Connaught Place ➡️ Delhi ➡️ 9999965857 🚀 No Advance 24HRS...
VVVIP Call Girls In Connaught Place ➡️ Delhi ➡️ 9999965857 🚀 No Advance 24HRS...VVVIP Call Girls In Connaught Place ➡️ Delhi ➡️ 9999965857 🚀 No Advance 24HRS...
VVVIP Call Girls In Connaught Place ➡️ Delhi ➡️ 9999965857 🚀 No Advance 24HRS...
 

"Удобный и расширяемый роутинг в iOS-приложении" Тимур Юсипов (Avito)

  • 1. Удобный и расширяемый роутинг в iOS-приложении Юсипов Тимур Avito
  • 2. Историческая справка 70187 lines of code 39051 lines of code (2011 .. 2013) Outsource (2013 .. 2016) In-house VIPER
  • 3. Введем понятие Router Как будет проходить презентация? Рассмотрим необычные задачи Routing’а Попробуем написать Router Адаптируем Router под iPad Сформулируем общие архитектурные правила Routing’а Посмотрим демо
  • 4. Что такое Module? Router View Controller MVC Model View View Interactor Router Presenter Entity VIPER RouterRouter View Controller MVC Model View View InteractorPresenter Entity VIPER
  • 7. 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
  • 8. protocol RouterProtocol: class { func showAuthorization() } Пробуем написать Router 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) } } 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
  • 9. Добавляем слой Assembly protocol 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 }
  • 10. Пробуем написать Router c Assembly 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() { 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) } } } Добавим базовый класс
  • 11. 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) } } } Вынесем в базовый класс
  • 12. 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 } } } Хороший фасад
  • 13. Базовый класс 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 нужен второй навигационный контроллер
  • 14. Второй базовый класс 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) } } } Добавим структурку для передачи всех нужных роутеру параметров
  • 15. Добавляем структурки struct RouterSeed { let navigationController: UINavigationController } struct RouterSeed { let navigationController: UINavigationController } struct MasterDetailRouterSeed { let masterNavigationController: UINavigationController let detailNavigationController: UINavigationController } Теперь рефакторить будет удобней
  • 16. Улучшенный фасад pushViewControllerDerivedFrom { routerSeed -> UIViewController inpushViewControllerDerivedFrom { 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
  • 17. So far, so good Модуль авторизации из всех модулей Поддержка DeepLinks Bonus: (Push’ы, Alert’ы) Нужно научить базовые роутеры искать верхний модуль So far, so good, но что если
  • 18. Поиск верхнего модуля 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 } } Нужна своя система навигации
  • 19. Зачем нужна своя система навигации? Хранение истории переходов Поддержка Third-party контроллеров Bonus: проверка, что модуль был на экране Bonus: расстояние между модулями Поиск верхнего модуля Обертка над UIKit Реакция на изменение SDK
  • 20. Свежий взгляд на базовый Router class 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’ов
  • 21. Абстрагируем 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 общается с обработчиком переходов
  • 22. Обработчик переходов оборачивает UIViewController Виды модулей Анимирующие AnimatingTransitionsHandlerImpl NavigationTransitionsHandlerImpl ContainerTransitionsHandlerImpl SplitViewTransitionsHandlerImpl TabBarTransitionsHandlerImpl Контейнеры pushViewController(_:animated:) presentViewController(_:animated:completion:) visibleAnimatingTransitionsHandlers() allAnimatingTransitionsHandlers() Легко добавить Third-party контроллер
  • 23. class BaseRouter { weak var navigationController: UINavigationController? weak var rootViewController: UIViewController? } Новый базовый Router 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? } 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’ом
  • 24. Схема выполнения отменяемых переходов Transitions handler box выполни отменяемый переход Router presentation context transitions handler box Transitions Coordinator Top animating transitions handlerзапусти анимацию presentation context
  • 25. Взглянем еще раз на новый базовый Router class 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? } Теперь роутер может закрывать свой модуль
  • 26. Навигационная связь Router 1 transition id 1 Transitions handler 1 Transitions handler 2 presenting transitions handler Вернись на модуль 1 Закрой модуль 2 Router 2 transition id 2 Что лучше: “Вернись на модуль 1” или “Закрой модуль 2” ?
  • 28. Выход из Flow Фильтр Города Router dismiss cities
  • 30. Выход из Flow Фильтр module output ГородаРегионы module output Router return to filter “Вернись на модуль” гибче, чем “Закрой модуль”
  • 31. Слой Router Предварительные итоги Подходы к выполнению обратных переходов Поддержка DeepLinks Слой Assembly Базовые классы Router, поддержка iPad, master-detail Простой Router (фасад, абстрация от UIKit, поддержка Third-Party)
  • 33. Один UIViewController, много Router’ов Выводы по демо Проверка наличия модуля в истории (Авторизация) Проверка isIpad() Поиск верхнего модуля (Авторизация, DeepLink’и, Push’ы) Проверка модулей на дубликаты (🍌, 🍏) Аниматоры переходов Проверка isIpad()
  • 34. Выделите слой Router (определять стиль перехода) Общие советы Используйте “Вернись на модуль” вместо “Закрой модуль” Выделите слой Assembly (верьте в появление DI для Swift) Абстрагируйте Router от UIKit Вынесите логику принятия решений в отдельный слой Описывайте переходы в декларативном стиле
  • 35. One more thing https://github.com/avito-tech/Marshroute Исходники Докладчик: Юсипов Тимур https://vk.com/ma3tsa tyusipov@avito.ru ykylele@gmail.com fizmatchelskype personal mail work mail vk Marshroute Спасибо за внимание! presentation.finish() https://github.com/avito-tech/Marshroute/tree/master/Example Демо