Стройные роутеры

В конце прошлого года я выкладывал презентацию и проект на GitHub, в которых рассказывал о роутерах — объектах, позволяющих вынести весь код, связанный с навигацией, из ViewController‘ов. Теперь я готов дополнить изложенную идею более стройной реализацией.

Итак, как обычно выглядит навигация между различными экранами?

Здесь мы видим сразу две проблемы:
1. Отвратительный if-else, да еще и приправленный сравнениями строчек.
2. Контроллер вообще не должен ничего знать о конкретной реализации переходов между различными экранами, в том числе и об интерфейсах других контроллеров.

Чего мы хотим добиться? Переход к следующему экрану должен быть инициирован вызовом простого метода вида:

Создадим класс DetailRouter и напишем реализацию этого метода:

Ни одной из обозначенных проблем мы этим не решили, лишь создали бесполезную сущность — такой она и останется, пока мы не вынесем самый тяжелый участок кода — метод prepareForSegue. На помощь приходит method swizzling. Первым делом, добавим базовый протокол, который должны будут реализовывать все наши будущие роутеры:

В нашу категорию UIViewController+Routing добавим property с абстрактным роутером. Теперь можно и немного посвиззлить:

Таким образом, при вызове prepareForSegue мы сначала вызываем его оригинальную имплементацию (если на по каким-то причинам есть), а затем дергаем соответствующий метод у нашего чудесного роутера. Бесполезная сущность наконец-то обрела смысл:

Текущая реализация все еще выглядит до ужаса печально. В презентации я рассказывал о способе передачи параметров в prepareForSegue при помощи словарика с userInfo. Такой вариант, к сожалению, не избавляет нас от необходимости вообще использовать этот метод, так что проблема №1 остается нерешенной. И здесь на помощь нам приходит:

Используя этот метод, мы можем задавать всю необходимую конфигурацию еще до вызова performSegueWithIdentifier:

Ну а чтобы все стало еще чуточку лучше, запилим базовый класс для наших роутеров и перенесем туда prepareForSegue. Теперь наши роутеры стали стройными и прекрасными — а ViewController‘ы еще чуточку синглреспонсибилистей.

Реализацию категории UIViewController+Routing можно посмотреть на GitHub. Пример использования — MultipleStoryboardsSample.
Viva Lighter View Controllers!

  • etolstoy

    Тест