Search code examples
iosswiftautolayoutnslayoutconstraint

Where do NSLayoutConstraint objects live when activated with .isActive = true?


I'm new to Swift. In an Apple development tutorial I found the following snippet of code

let button = UIButton() 
button.widthAnchor.constraint(equalToConstant:44.0).isActive = true

Can someone help me understanding what happens with the latter line?

widthAnchor is a computed property of button, and its type is NSLayoutDimension.

constraint(equalToConstant:) is a method of NSLayoutDimension class returning a

NSLayoutConstraint object.

Hence ... .isActive = true sets the isActive property of the latter object to true.

Where does that object "live" and how is it related to button object?

Thanks


Solution

  • UIButton is a subclass of UIView and thus it has a constraints property that is [NSLayoutConstraint].

    The NSLayoutConstraint that you create is an object (so it is allocated on the heap) and a reference to it is added to the constraints property of the button itself:

    let button = UIButton()
    
    print(button.constraints)
    
    []  // empty array
    
    button.widthAnchor.constraint(equalToConstant:44.0).isActive = true
    
    print(button.constraints)
    
    [<NSLayoutConstraint:0x6000000926b0 UIButton:0x7fbe6ff01940.width == 44   (active)>]
    

    An NSLayoutConstraint is related to up to two items (views). When you activate an NSLayoutConstraint, iOS adds a reference to that constraint to the constraints property of the appropriate UIView subclass. The appropriate view depends on the relationship of the two items in the constraint.

    relationship          add to
    ------------          ------
    siblings              parent of the two siblings
    parent/child          parent
    single view           view
    other                 first common ancestor
    

    The first is just a specific case of the last, but I left it here for clarity.


    Siblings Example

    Here is a siblings example. button1 and button2 are subviews of container, so a reference to the constraint that relates button1's height to button2's height gets added to constraints array for container which is their parent view:

    let button1 = UIButton()
    let button2 = UIButton()
    let container = UIView()
    
    container.addSubview(button1)
    container.addSubview(button2)
    
    button1.heightAnchor.constraint(equalTo: button2.heightAnchor, multiplier: 2).isActive = true
    
    print(container.constraints)
    
    [<NSLayoutConstraint:0x60800008ef10 UIButton:0x7f9ec7c03740.height == 2*UIButton:0x7f9ec7d06f90.height   (active)>]