0

I have a Xcode 16.3 Swift/UIKit project that does programmtically setup a UITabBarController in SceneDelegate like so:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let windowScene = (scene as? UIWindowScene) else { return }

    window = UIWindow(windowScene: windowScene)

    let vc1 = UIViewController()
    vc1.view.backgroundColor = .systemRed
    vc1.title = "Hello"
    let nc1 = UINavigationController(rootViewController: vc1)
    
    let vc2 = UIViewController()
    vc2.view.backgroundColor = .systemGreen
    vc2.title = "World"
    let nc2 = UINavigationController(rootViewController: vc2)

    let tb = UITabBarController()
    window?.rootViewController = tb
    window?.makeKeyAndVisible()
    
    tb.viewControllers = [nc1, nc2]
}

This is giving me layout constraint errors on iPadOS (not on iOS) as soon as I switch to the second "World" tab:

Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<NSLayoutConstraint:0x600002139400 UILayoutGuide:0x600003b089a0'TitleView(layout=0x1035110f0)'.trailing <= UILayoutGuide:0x600003b08d20'UIViewLayoutMarginsGuide'.trailing   (active)>",
    "<NSLayoutConstraint:0x600002147480 H:|-(338)-[UILayoutGuide:0x600003b09180'TabBarGuide(0x103510de0)'](LTR)   (active, names: '|':_UINavigationBarContentView:0x103510de0 )>",
    "<NSLayoutConstraint:0x600002147610 UILayoutGuide:0x600003b09180'TabBarGuide(0x103510de0)'.width == 158   (active)>",
    "<NSLayoutConstraint:0x600002147980 UILayoutGuide:0x600003b089a0'TitleView(layout=0x1035110f0)'.trailing >= UILayoutGuide:0x600003b09180'TabBarGuide(0x103510de0)'.trailing   (active)>",
    "<NSLayoutConstraint:0x600002147b10 'UIView-Encapsulated-Layout-Width' _UINavigationBarContentView:0x103510de0.width == 0   (active)>",
    "<NSLayoutConstraint:0x600002138af0 'UIView-rightMargin-guide-constraint' H:[UILayoutGuide:0x600003b08d20'UIViewLayoutMarginsGuide']-(0)-|(LTR)   (active, names: '|':_UINavigationBarContentView:0x103510de0 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x600002139400 UILayoutGuide:0x600003b089a0'TitleView(layout=0x1035110f0)'.trailing <= UILayoutGuide:0x600003b08d20'UIViewLayoutMarginsGuide'.trailing   (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.

When I simply change from:

tb.viewControllers = [nc1, nc2]

to:

tb.viewControllers = [vc1, vc2]

the errors go away.

What is wrong here?

3
  • You should update this question and explain how it's different from your previous question. You accepted an answer in that other question but this question seems no different than that other one. Commented May 16 at 14:45
  • It's interesting that the same conflict arises, on both navigation controllers, if you create the whole hierarchy in the storyboard. I would suggest that you just ignore the issue (and perhaps file a bug report with Apple). This is a legal architecture and should not behave badly like this. Commented May 16 at 14:59
  • @HangarRash the difference is that the OP has now realized that you get the conflict message when you switch to the second tab, even though we managed to avoid getting it at launch on the first tab. Commented May 16 at 15:00

1 Answer 1

1

This is ultimately Apple's bug. You should report it and (for purposes of your app) ignore it.

One way to prove this to yourself is that the same view hierarchy created entirely in the storyboard behaves the same way — you get the autolayout conflict on the first appearance of each tab.

Another way is to reject Apple's new "floating tab bar" (the interface with the tab bar at the top), as described in How to disable the new UITabBarController view style in iPadOS 18. When you do, the issue goes away.

So the problem is caused by some interaction of the new "floating tab bar" with the navigation bar, which sort of makes sense in that the "floating tab bar" covers the navigation bar; and you shouldn't worry about it. But, since the tab bar does cover the navigation bar, it might be best not use this architecture at all, i.e. don't put a navigation controller inside a tab bar controller in the first place.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.