Для иллюстрации предположим, что ситуация в раскадровке следующая:
ViewController1
|----> modal segue "toVC2" emanating from ViewController1
|----> ViewController2, identifier "VC2"
Тогда в коде ViewController1 нет абсолютно никакой функциональной или эффективной разницы между этими двумя вещами:
- Звоните
performSegue
с идентификатором "toVC2"
- Позвоните
instantiateViewController
на раскадровку с идентификатором "VC2"
и позвоните present
Сказав это, я приведу аргументы в пользу того, что каждый способ "лучше", чем другой.
Почему результат может быть лучше
Последовательность в моем примере выглядит не намного лучше, потому что мы все еще должны использовать код для вызова performSegue
. Однако предположим, что переход исходит не от контроллера вида, а от кнопки в виде контроллера вида. Это действие segue, и теперь оно будет выполняться автоматически , когда пользователь нажимает на нашу кнопку, с кодом , необходимым для его выполнения. Вам даже не нужно знать идентификатор. (Строковые идентификаторы - отличный способ ошибиться.)
Почему instantiate
и present
могут быть лучше
В сегментах segues есть что-то очень ужасное, будь то последовательность действий или сценарий, запускаемый вручную с помощью performSegue
, а именно, когда (как это часто случается) вы хотите передать данные с первого контроллера представления на второй. Если вы используете segue, вы должны выполнить передачу данных в реализации prepare(for:sender:)
. Это очень грязно, потому что вы должны проверить идентификатор сегмента и привести целевой класс к правильному классу. Более того, если есть более одного перехода, prepare
становится грязным узким местом. И если мы также назвали performSegue
, мы работаем в двух разных местах - метод, в котором мы назвали performSegue
, и отдельная реализация prepare
.
Напротив, если мы вызываем instantiateViewController
, то, что возвращается к нам, это сам экземпляр контроллера представления. Нам по-прежнему необходимо выполнить приведение, но теперь мы можем передавать данные прямо здесь и сейчас, не ожидая prepare
и не проходя через узкое место. Таким образом, это гораздо более разборчивый и инкапсулированный способ судебного разбирательства.
Кроме того, это может показаться очевидным, но хорошо сказать, что present
заключается в том, что это прямо говорит нам в коде, что переход равен . Если вы просто используете идентификатор сегмента, тот факт, что это модальный переход, скрыт в раскадровке.
Что я предпочитаю?
Ни. Я предпочитаю вообще не использовать раскадровки для представленных контроллеров представления, если могу помочь. Я использую контроллер вида и одноименное перо. Таким образом, я просто создаю экземпляр самого контроллера представления и передаю ему данные и present
его, без необходимости приведения и без каких-либо идентификаторов.
Так я говорю, что раскадровки не годятся?
Нет. Раскадровки имеют свойство отображать структуру сцены вашего приложения, особенно если вы используете сегменты. Однако, если вы не собираетесь использовать переход к контроллеру представления, то я не вижу смысла сохранять этот контроллер представления в раскадровке. Механизм одноимённого кончика становится чище и чище. Более того, я рассматриваю механизм prepare(for:sender:)
как почти фатальный недостаток во всей архитектуре раскадровки; огромное количество ошибок, показанных в переполнении стека, является следствием этого недостатка.
[ EDIT Обратите внимание, что многие из моих возражений против сегментов отпадут в iOS 13, где контроллер представления источника сможет использовать код для вызова инициализатора контроллера представления назначения.]