Нарушает ли вложение UINavigationController в другой UINavigationController принцип подстановки Барбары Лисков (LSP)?

Ответ

Да, это прямое нарушение LSP.

Принцип Лисков гласит, что объекты должны быть заменяемыми экземплярами своих базовых классов без изменения корректности программы.

UINavigationController не спроектирован для использования в качестве viewController внутри стека другого UINavigationController. Такая вложенность приводит к:

  • Непредсказуемому поведению навигационной панели (появлению двух панелей, конфликтам кнопок back).
  • Проблемам с жестами (например, interactivePopGestureRecognizer).
  • Нарушению ожидаемого жизненного цикла и контейнерной иерархии UIKit.

Неправильный подход (нарушает LSP):

let innerNavController = UINavigationController(rootViewController: SomeViewController())
let outerNavController = UINavigationController(rootViewController: innerNavController) // Нарушение!
window?.rootViewController = outerNavController

Правильные альтернативы:

  1. Использовать UINavigationController как корневой контейнер, а внутри стека размещать только UIViewController.
  2. Для сложной навигации использовать комбинацию UITabBarController и UINavigationController.
  3. Реализовать кастомный контейнерный контроллер, если требуется особая логика переходов.

Ответ 18+ 🔞

А, ну вот, опять наехали на бедный LSP, как на гречку в столовой. Слушай, а ты в курсе, что этот принцип — не просто умное слово из книжки, а реально, блядь, страховка от пиздеца в коде? Вот представь, ты пишешь программу, а она ведёт себя как пьяный ёжик в тумане. Почему? А потому что кто-то решил, что можно впихнуть невпихуемое.

Вот смотри, есть у нас UINavigationController. Штука полезная, как унитаз в квартире. Но он, сука, не резиновый! Он спроектирован быть верховным главнокомандующим для стека вьюконтроллеров, а не рядовым солдатиком в другом таком же стеке.

Если ты попробуешь сделать вот эту хуйню:

let innerNavController = UINavigationController(rootViewController: SomeViewController())
let outerNavController = UINavigationController(rootViewController: innerNavController) // Нарушение!
window?.rootViewController = outerNavController

То получишь, ёпта, целый букет геморроя:

  • Две навигационных панели. Одна сверху говорит «Назад», другая снизу тоже орет «Назад!». Они начинают драться за твой тап, как два кота за сосиску. Кто победит? А хуй его знает, это уже лотерея от Apple.
  • Жесты отваливаются. Этот красивый свайп назад, чтобы вернуться? Забудь. Он теперь работает когда захочет, а чаще всего — вообще нихуя не работает.
  • Жизненный цикл сходит с ума. Контроллеры внутри начинают получать странные сообщения, появляться и исчезать в непонятном порядке. В общем, ёперный театр, а не приложение.

Это и есть нарушение LSP в чистом виде. Ты подсовываешь системе UINavigationController и говоришь: «Вот тебе обычный UIViewController, работай с ним». А система, доверчивая дура, пытается с ним работать как с обычным. А он-то, гад, внутри себя ещё целый стек контроллеров держит и свою собственную навигационную логику! Получается «матрёшка», которая всех ебёт.

Так что же делать, если нужна сложная навигация? Не выёбывайся, а делай по-человечески:

  1. UINavigationController — он один и корневой. Внутри его стека — только обычные UIViewController. Как матрёшка, но с одной куклой внутри, а не с целым детским садом.
  2. Нужны вкладки? Бери UITabBarController в корень, а в каждую вкладку клади отдельный UINavigationController. Это как этажерка: сверху табы, а в каждом ящике — свой независимый навигационный стек. Красота!
  3. Захотелось совсем уж дикой, кастомной навигации? Ну что ж, делай свой собственный контейнерный контроллер, наследник от UIViewController. Пиши свою логику переходов, анимаций, жопоруких жестов. Это сложно, зато честно и без сюрпризов.

Короче, запомни, как «Отче наш»: Не вкладывай UINavigationController в другой UINavigationController. Это всё равно что пытаться надеть один презерватив на другой — надёжнее не станет, а порваться и всё испортить — запросто. Делай по правилам, и твой код не будет вызывать у следующих разработчиков тихого, ебучого ужаса.