Ответ
Да, это прямое нарушение LSP.
Принцип Лисков гласит, что объекты должны быть заменяемыми экземплярами своих базовых классов без изменения корректности программы.
UINavigationController не спроектирован для использования в качестве viewController внутри стека другого UINavigationController. Такая вложенность приводит к:
- Непредсказуемому поведению навигационной панели (появлению двух панелей, конфликтам кнопок
back). - Проблемам с жестами (например,
interactivePopGestureRecognizer). - Нарушению ожидаемого жизненного цикла и контейнерной иерархии UIKit.
Неправильный подход (нарушает LSP):
let innerNavController = UINavigationController(rootViewController: SomeViewController())
let outerNavController = UINavigationController(rootViewController: innerNavController) // Нарушение!
window?.rootViewController = outerNavController
Правильные альтернативы:
- Использовать
UINavigationControllerкак корневой контейнер, а внутри стека размещать толькоUIViewController. - Для сложной навигации использовать комбинацию
UITabBarControllerиUINavigationController. - Реализовать кастомный контейнерный контроллер, если требуется особая логика переходов.
Ответ 18+ 🔞
А, ну вот, опять наехали на бедный LSP, как на гречку в столовой. Слушай, а ты в курсе, что этот принцип — не просто умное слово из книжки, а реально, блядь, страховка от пиздеца в коде? Вот представь, ты пишешь программу, а она ведёт себя как пьяный ёжик в тумане. Почему? А потому что кто-то решил, что можно впихнуть невпихуемое.
Вот смотри, есть у нас UINavigationController. Штука полезная, как унитаз в квартире. Но он, сука, не резиновый! Он спроектирован быть верховным главнокомандующим для стека вьюконтроллеров, а не рядовым солдатиком в другом таком же стеке.
Если ты попробуешь сделать вот эту хуйню:
let innerNavController = UINavigationController(rootViewController: SomeViewController())
let outerNavController = UINavigationController(rootViewController: innerNavController) // Нарушение!
window?.rootViewController = outerNavController
То получишь, ёпта, целый букет геморроя:
- Две навигационных панели. Одна сверху говорит «Назад», другая снизу тоже орет «Назад!». Они начинают драться за твой тап, как два кота за сосиску. Кто победит? А хуй его знает, это уже лотерея от Apple.
- Жесты отваливаются. Этот красивый свайп назад, чтобы вернуться? Забудь. Он теперь работает когда захочет, а чаще всего — вообще нихуя не работает.
- Жизненный цикл сходит с ума. Контроллеры внутри начинают получать странные сообщения, появляться и исчезать в непонятном порядке. В общем, ёперный театр, а не приложение.
Это и есть нарушение LSP в чистом виде. Ты подсовываешь системе UINavigationController и говоришь: «Вот тебе обычный UIViewController, работай с ним». А система, доверчивая дура, пытается с ним работать как с обычным. А он-то, гад, внутри себя ещё целый стек контроллеров держит и свою собственную навигационную логику! Получается «матрёшка», которая всех ебёт.
Так что же делать, если нужна сложная навигация? Не выёбывайся, а делай по-человечески:
UINavigationController— он один и корневой. Внутри его стека — только обычныеUIViewController. Как матрёшка, но с одной куклой внутри, а не с целым детским садом.- Нужны вкладки? Бери
UITabBarControllerв корень, а в каждую вкладку клади отдельныйUINavigationController. Это как этажерка: сверху табы, а в каждом ящике — свой независимый навигационный стек. Красота! - Захотелось совсем уж дикой, кастомной навигации? Ну что ж, делай свой собственный контейнерный контроллер, наследник от
UIViewController. Пиши свою логику переходов, анимаций, жопоруких жестов. Это сложно, зато честно и без сюрпризов.
Короче, запомни, как «Отче наш»: Не вкладывай UINavigationController в другой UINavigationController. Это всё равно что пытаться надеть один презерватив на другой — надёжнее не станет, а порваться и всё испортить — запросто. Делай по правилам, и твой код не будет вызывать у следующих разработчиков тихого, ебучого ужаса.