Skip to content

Latest commit

 

History

History
41 lines (26 loc) · 6.48 KB

module-transitions.md

File metadata and controls

41 lines (26 loc) · 6.48 KB

Переходы между модулями - введение

Подход к созданию модулей через фабрику, описываемый в статьях про канонический VIPER, достаточно неудобен. Мы решили попробовать родные UIStoryboardSegue для переходов между модулями. Такой подход открывал заманчивые перспективы - ведь для перехода в другой модуль необходимо было бы всего лишь указать SegueID и передать в модуль данные для работы. Кроме того, для конфигурации модулей мы используем Typhoon, поэтому все модульные ViewController после инициализации через Segue уже имеют связи с другими компонентами модуля.

Переходы между модулями - через ViewController

Это самый простой вариант. У роутера вызывающего модуля есть ссылка на свой ViewController, при переходе на другой модуль у ViewController вызывается метод -prepareForSegue:, где в sender передаются данные для следующего модуля. Внутри -prepareForSegue: вызывающего ViewController эти данные передаются в следующий модуль.

Такой подход работает, но есть и некоторые недостатки:

  • Логика настройки следующего модуля размещается внутри View, а не в Router,
  • Нет универсальности и переиспользования, этот метод нужно реализовывать в каждом модуле,
  • Данные для работы следующего модуля попадают во View, а не в Presenter,
  • Каждый модуль знает об устройстве другого модуля,
  • Каждый роутер знает, что работает с классом UIViewController, и схема работает только для этого варианта.

Переходы между модулями - через ViewController c блоком конфигурации

Для решения первых двух проблем были использованы method-swizzling и блоки. В -prepareForSegue: в sender отправляется блок, в котором выполяется настройка модуля через destinationViewController. В альтернативном методе -prepareForSegue: блок вызывается с destinationViewController из segue в качестве параметра.

Это работает, логика настройки следующего модуля находится целиком внутри Router, для каждого модуля больше не требуется добавлять во ViewController метод -prepareForSegue:, но остаются три проблемы:

  • Данные для работы следующего модуля попадают во View, а не в Presenter,
  • Каждый модуль знает об устройстве другого модуля,
  • Каждый роутер знает, что работает с ViewController и схема работает только для этого.

Переходы между модулями - много протоколов

Чтобы решить оставшиеся проблемы были использованы протоколы. Много протоколов. А также swizzling и своя реализация promise. В итоге получилась система передачи данных между модулями без перечисленных недостатков, данные из презентера отдаются роутеру и он конфигурирует ими презентер следующего модуля. Но появились две новые проблемы:

  • На освоение у нового разработчика уходило порядка 2х дней,
  • Данные передавались только в одну сторону.

Переходы между модулями - вариант с ModuleInput

Текущий вариант, доступный в нашем Github под названием ViperMcFlurry стал гораздо проще в освоении. У каждого модуля теперь есть точка входа - ModuleInput, которая позволяет настроить модуль или вызывать методы. Этот moduleInput можно использовать внутри роутера для настройки модуля, можно вернуть презентеру, для постоянной связи с подмодулем. У каждого модуля можно задать ModuleOutput, чтобы вернуть данные из модуля. ModuleInput/Output - это протоколы, которые задаются внутри модуля, то есть в них хранится контракт связи с ним. В большинстве модулей в роли ModuleInput выступает презентер этого модуля, а в качестве ModuleOutput - презентер вызывающего модуля.

Embed Segue

Поскольку для метода -performSegue требуется только имя перехода, -prepareForSegue: подвергся swizzle'ингу, а Typhoon настраивает модуль по ViewController, то мы можем использовать любые классы Segue и механизм переходов между модулями будет работать.

Поэтому для встраивания модулей был создан специальный тип UIStoryboardSegue EmbedSegue. Внутри -performSegue у SourceViewController вызывается метод, который возвращает View для идентификатора Segue. В эту View и встраивается модуль.