0

I want to add container view to the main view (rootViewController.view), but the following gives exception. I know it about the constraints but not able to find out why.

import UIKit

class rootViewController : UIViewController {

    init() {
        super.init(nibName: nil, bundle: nil)
        setupLoginView()
    }

    func setupLoginView() {

        // User ID label
        let userIDLabel:UILabel = UILabel()
        userIDLabel.text = "User ID"

        // Password label
        let passwordLabel:UILabel = UILabel()
        passwordLabel.text = "Password"

        // User ID text
        let userIDText:UITextField = UITextField()

        // Password text
        let passwordText:UITextField = UITextField()

        // Login button
        let loginBtn:UIButton = UIButton()
        loginBtn.setTitle("Login", for: .normal)

        // Container view
        let container:UIView = UIView()

        container.addSubview(userIDLabel)
        container.addSubview(userIDText)
        container.addSubview(passwordLabel)
        container.addSubview(passwordText)
        container.addSubview(loginBtn)

        view.addSubview(container)

        // Add constraints
        let heightConstraint = NSLayoutConstraint(item: container, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 300)
        let widthConstraint = NSLayoutConstraint(item: container, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 200)
        let centerXConstraint = NSLayoutConstraint(item: container, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1, constant: 0)
        let centerYConstraint = NSLayoutConstraint(item: container, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1, constant: 0)

        container.addConstraint(heightConstraint)
        container.addConstraint(widthConstraint)
        container.addConstraint(centerXConstraint)
        container.addConstraint(centerYConstraint)

    }

}

Gives the following exception, with hint "Does the constraint reference something from outside the subtree of the view? That's illegal"

'NSGenericException', reason: 'Unable to install constraint on view. Does the constraint reference something from outside the subtree of the view? That's illegal. constraint: NSLayoutConstraint:0x170089830 UIView:0x12de138c0.centerX == UIView:0x12de0e650.centerX (active)>

MGY
  • 7,245
  • 5
  • 41
  • 74
Clinton Lam
  • 687
  • 1
  • 8
  • 27

4 Answers4

1

Replace your code for adding the center constraints with these lines:

view.addConstraint(centerXConstraint)
view.addConstraint(centerYConstraint)

You can't add a constaint on the container with a reference to it's superview.

And move the setupLoginView() to viewDidLoad instead of init().

Don't forget to remove the warning in the console to set translatesAutoresizingMaskIntoConstraints to false for all the created views (container, labels, buttons and textviews).

Pranav Kasetti
  • 8,770
  • 2
  • 50
  • 71
1

1. Move setupLoginView() to viewDidLoad()

override func viewDidLoad()
{
    super.viewDidLoad()
    setupLoginView()
}

2. Set translatesAutoresizingMaskIntoConstraints of container

    container.translatesAutoresizingMaskIntoConstraints = false

3. Add constraints to relevant views:

    container.addConstraint(heightConstraint)
    container.addConstraint(widthConstraint)
    view.addConstraint(centerXConstraint)
    view.addConstraint(centerYConstraint)
PGDev
  • 23,751
  • 6
  • 34
  • 88
0

The ViewController's view does not exist yet. Move the setupLoginView() call from the init() method to viewDidLoad().

Also - as @Pranav Kasetti suggests - you have to add the center constraints to the view instead of the container.

Last but not least set translatesAutoresizingMaskIntoConstraints to false for all the created views (including the container).

André Slotta
  • 13,774
  • 2
  • 22
  • 34
0

The problem is that you define properties in the init method, but it's not the good entry point for a ViewController. You should take a look here for some details.

Then, replace

init() {
    super.init(nibName: nil, bundle: nil)

by this:

override func viewDidLoad() {
    super.viewDidLoad()

and it should works.

Maxime
  • 1,332
  • 1
  • 15
  • 43