Ответ
Да, это прямое нарушение LSP. Принцип гласит, что объекты подклассов должны быть заменяемы на объекты родительских классов без изменения корректности программы.
UINavigationController является подклассом UIViewController. По логике, мы должны иметь возможность поместить любой UIViewController в стек навигации. Однако UINavigationController нарушает контракт базового класса:
- Нарушение ожидаемого поведения: Вложенный
UINavigationControllerсоздаст собственную панель навигации внутри чужой, что приведет к путанице (две панели навигации), нестандартным жестам и сложностям с кнопкой "Назад". - Нарушение инвариантов: Клиентский код, работающий со стеком
UIViewController, не ожидает, что внутри может быть контроллер, который сам управляет своим стеком.
Правильные альтернативы:
-
Использовать обычные
UIViewController:// Вместо вложенного NavigationController let detailVC = DetailViewController() navigationController?.pushViewController(detailVC, animated: true) -
Использовать контейнерные контроллеры (
UIViewController.addChild): Для сложных интерфейсов. -
Использовать координаторы/роутеры: Вынести логику навигации из вью-контроллеров в отдельный слой.
-
Модальный презент: Если нужен независимый поток, представьте новый
UINavigationControllerмодально.let modalFlow = UINavigationController(rootViewController: StartViewController()) present(modalFlow, animated: true)
Нарушение LSP здесь ведет к хрупкому, труднотестируемому и непредсказуемому коду.
Ответ 18+ 🔞
А, ну это же классика, блядь! Смотри, тут про принцип подстановки Барбары Лисков, ебать мои старые костыли. Говорит он, что если у тебя есть родительский класс, то на его место можно подставить любой дочерний, и всё должно работать, как часы, а не как говно в проруби.
Так вот, UINavigationController — это подкласс UIViewController. По идее, по логике, по заветам дедов, мы должны иметь право запихнуть любой UIViewController в стек навигации. Но этот пидарас шерстяной, UINavigationController, взял и нагло нарушил контракт, блядь!
Почему? Да потому что он, сука, ведёт себя не так, как от него ожидают.
- Ожидания vs. Реальность, пиздец. Ты засунул один
UINavigationControllerвнутрь стека другого. И что? А он, хитрая жопа, начинает лепить свою собственную панель навигации внутри чужой! Получается пиздопроебибна: две панели навигации, жесты накладываются друг на друга, кнопка «Назад» ведёт себя так, будто её нахуй послали. Клиентский код, который работает с обычными вьюхами, просто охуевает от такого цирка. - Инварианты? Какие инварианты? Код, который крутит стек
UIViewController, не ожидает, что внутри может сидеть контроллер, который сам себе царь и бог, и у него свой собственный стек. Это как вставить холодильник в микроволновку — вроде оба кухонная техника, но нихуя не работает.
Так что же делать, ёпта? Не быть мудаком, как этот Герасим из рассказа, который сразу мочить полез.
- Используй обычные
UIViewController, блядь. Вместо того чтобы городить вложенную навигацию, просто пушай нормальный контроллер.// Не надо вкладывать UINavigationController, не выёбывайся! let detailVC = DetailViewController() navigationController?.pushViewController(detailVC, animated: true) - Контейнеры в помощь. Для сложных интерфейсов есть
UIViewController.addChild(). Это как раз для таких умников, которым мало одного экрана. - Вынеси навигацию нахуй. Используй координаторы или роутеры. Пусть вьюхи не знают, куда их швыряют, этим пусть отдельный слой занимается.
- Модально представь. Если тебе нужен отдельный, независимый поток экранов — представь новый
UINavigationControllerмодально, и пусть он живёт своей жизнью.let modalFlow = UINavigationController(rootViewController: StartViewController()) present(modalFlow, animated: true)
Вот и весь сказ. Нарушаешь LSP — получаешь код, который хрупкий, как яичко фазана, непредсказуемый, как погода в Питере, и тестируется с таким же удовольствием, как поиск иголки в стоге сена, облитом бензином. Не делай так.