Роутер

Определение

👉
Роутер — это сервис, который инкапсулирует UI-логику.

В контексте iOS роутер изолирует остальную часть приложения от UIKit, т.е. создание создание всех UIViewController, UINavigationController, UITabBarController и их монтаж на UIWindow выполняется исключительно внутри роутера. Роутер отделен от всех прочих сервисов по двум причинам.

Во-первых, в UI сосредоточена большая часть различий между платформами. Инкапсуляция этих различий в отдельной сущности позволяет использовать кроссплатформенную бизнес-логику. Кроссплатформенные решения, которые игнорируют или пытаются маскировать эти UI-различия платформ, не обеспечивают «нативного look-and-feel». Побочным эффектом применения роутера также является возможность разрабатывать приложение в «headless-режиме», используя вместо настоящего роутера mock-объект. Это открывает широкие возможности для интеграционного тестирования.

Во-вторых, UI современных клиенстких приложений обладает собственным состоянием, которое надо:

  • хранить;
  • модифицировать согласно UI-логике;
  • синхронизировать с бизнес-логикой.

Именно за эти процессы и отвечает роутер, что позволяет разрабатывать UI независимо от бизнес-логики, равно как и разрабатывать бизнес-логику, независимо от UI. Сообщения для роутера параметризуются вью-моделями, которые предоставляют роутеру полный контекст вызова. Роутер хранит свой внутренний контекст, который он самостоятельно сопоставляет с вызывающим контекстом из вью-модели, после чего принимает то или иное решение.

Графическое представление

Как и любой другой сервис, роутер описывается диаграммой состояний.

Примеры

Рассмотрим пример UI-логики. У вас приложение-магазин. В приложении есть экран с каталогом товаров, экран с карточкой товара и экран настроек. Вам поступила задача от маркетинга: обрабатывать диплинк с акцией  «Носки со скидкой 90%», т.е. уметь открывать карточку акционного товара в произвольный момент времени. При этом требование UX-проектировщика — не прерывать пользовательский контекст при открытии акционной карточки. Это означает, что UI-логика открытия диплинка зависит от контекста:

  • если пользователь находится на вкладке с каталогом товаров, то акционную карточку следует открыть через push в UINavigationController каталога, так же, как открываются все остальные карточки товаров;
  • если пользователь уже находится на карточке товара, то:
    • в случае совпадения текущей и акционной карточек ничего не делаем;
    • в случае различия снова выполняем push карточки в навигационный стек;
  • если пользователь находится на вкладке с настройками, где навигационного стека не предусмотрено, то карточку акционного товара показываем модально.

Детали реализации

Применительно к iOS инстанцирование вью-контроллеров можно перенести из роутера в фабрику вью-контроллеров. Таким образом, в роутере останется «чистая» UI-логика, которую можно покрыть тестами точно так же, как это делается с любым другим сервисом.