iosswiftautolayoutanchoruiview-hierarchy

Auto Layout constraint crashes due to anchor in a "different" view hierarchy in iOS, but


I am working in an iOS 11.X app with Swift 4.1, fully programatic. Using Xcode 9.4

I am trying to have a view centered in the middle (horizontally), with a distance of 10 pts to the top of the view, with rotation support.

The app architecture has the regular stuff, as follows (no storyboard):

Given that in landscape mode, the statusBar is not visible and to simplify the autolayout configuration, I decided to add a top anchor to the navigationBar as follows (code was simplified for clarity):

let navBar = self.navigationController!.navigationBar
let label = UILabel()
label.backgroundColor = .yellow
label.text = "TEXT"
label.textAlignment = NSTextAlignment.center
self.view.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.widthAnchor.constraint(equalToConstant: 50).isActive = true
label.heightAnchor.constraint(equalToConstant: 20).isActive = true
label.centerXAnchor.constraint(equalTo: label.superview!.centerXAnchor).isActive = true
label.topAnchor.constraint(equalTo: navBar.bottomAnchor, constant: 10).isActive = true

The result is as expected. It rotates nicely, and also works fine if the App is launched in landscape or portrait (both in the device and in the simulator).

PORTRAIT enter image description here

LANDSCAPE enter image description here

Now. FastForward 1 commit in GitHub, with no changes in the overall App View Architecture, and the same code, it crashes with the following message

*** NSGenericException', reason: 'Unable to activate constraint with anchors and because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal.

Any idea of what may be going on here?. I downloaded the .zip from the previous GitHub commit to have it isolated and to re-confirm that it works!!. But the current commit fails without no changes to the code related to this UILabel.

The navBar is part of UIWindow->UILayoutContainerView->UINavigationBar


Solution

  • I was able to identify what causes the crash.

    The only difference in the last commit is a small delay (before adding the UI elements and the constraints). 0.01 seconds are enough and it works fine as follows:

    import UIKit
    class ViewController: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
            self.title = "APP TITLE"
            self.view.backgroundColor = .white
            Timer.scheduledTimer(withTimeInterval: 0.01, repeats: false) { (nil) in
                let navBar = self.navigationController!.navigationBar
                let label = UILabel()
                label.backgroundColor = .yellow
                label.text = "TEXT"
                label.textAlignment = NSTextAlignment.center
                self.view.addSubview(label)
                label.translatesAutoresizingMaskIntoConstraints = false
                label.widthAnchor.constraint(equalToConstant: 50).isActive = true
                label.heightAnchor.constraint(equalToConstant: 20).isActive = true
                label.centerXAnchor.constraint(equalTo: label.superview!.centerXAnchor).isActive = true
                label.topAnchor.constraint(equalTo: navBar.bottomAnchor, constant: 10).isActive = true
            }
        }
    }
    

    You will find a clean Xcode project with the working code here https://www.dropbox.com/s/vhd9emd8ixf5lbs/AutoLO.zip?dl=0

    Comment the Timer.scheduledTimer(withTimeInterval: repeats:) lines and it will crash with the message:

    *** Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to activate constraint with anchors NSLayoutYAxisAnchor:0x60c000267e80 "UILabel:0x7fe0ede0b960'TEXT'.top" and NSLayoutYAxisAnchor:0x60c000267f00 "UINavigationBar:0x7fe0edd06ce0.bottom" because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal.

    The explanation of why Xcode complains about a centerY / YAxis anchor when there is none, is a mystery to me.