Ответ
Да, это прямое нарушение 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 здесь ведет к хрупкому, труднотестируемому и непредсказуемому коду.