Search code examples
iosswiftautolayoutnslayoutconstraint

iOS constraint style: addConstraints vs .isActive = true


I have some code which is creating auto-layout constraints programatically, and adding them to a view.

There are two ways to do this - call addConstraints on the superView, or set .isActive = true on each constraint (which internally calls addConstraint)

Option 1:

parent.addConstraints([
    child.topAnchor.constraint(equalTo: parent.topAnchor, constant: 20),
    child.leftAnchor.constraint(equalTo: parent.leftAnchor, constant: 5) ])

Option 2:

child.topAnchor.constraint(equalTo: parent.topAnchor, constant: 20).isActive = true
child.leftAnchor.constraint(equalTo: parent.leftAnchor, constant: 5).isActive = true

My question is, is there any benefit to doing one over the other? (performance/etc) or does it come purely down to style.

(I don't think constraints are evaluated until the next layout pass, so I don't think it should matter that we add them one-by-one instead of in a block??)

If it is just style, what's the "more preferred" style by the community??

(personally I prefer addConstraints, however it's very close and I could be easily swayed to .isActive)


Solution

  • According to the documentation on addConstraint: setting the active property is recommended for individual constraints. (note: active property is only available iOS 8+).

    When developing for iOS 8.0 or later, set the constraint’s active property to YES instead of calling the addConstraint: method directly. The active property automatically adds and removes the constraint from the correct view. (reference)

    Also if you look at the interface definition for addConstraint: it has this comment:

    // This method will be deprecated in a future release and should be avoided.  Instead, set NSLayoutConstraint's active property to YES


    With that being said, there is actually a 3rd [and probably better] alternative, which is to use NSLayoutConstraint's class method activate::

    NSLayoutConstraint.activate([
        child.topAnchor.constraint(equalTo: parent.topAnchor, constant: 20),
        child.leftAnchor.constraint(equalTo: parent.leftAnchor, constant: 5) ])
    

    This is also a recommended solution according to the documentation and interface files. So if you have multiple constraints, this would be an easy solution and probably preferred in your situation.

    (interface comment; emphasis mine):

    Convenience method that activates each constraint in the contained array, in the same manner as setting active=YES. This is often more efficient than activating each constraint individually.