Why weak IBOutlet NSLayoutConstraint turns to nil when I make it inactive?
Asked Answered
S

3

51

I have an IBOutlet NSLayoutConstraint in my app. Very simple:

@property (nonatomic, weak) IBOutlet NSLayoutConstraint* leftConstraint;

At some point I want to deactivate this constraint:

self.leftConstraint.active = NO;

It happens in a method called from cellForRowAtIndexPath:. And the constraint becomes nil right after the line above. However if I declare this property as strong then it's ok, it doesn't turn to nil. Can anybody explain why it happens?

Subsidy answered 27/6, 2016 at 10:42 Comment(0)
A
101

When your outlet is weak, the only strong reference is from the view's constraints property. Deactivating the constraint removes it from that array, so there are no more strong references.

Araiza answered 27/6, 2016 at 10:44 Comment(6)
Elementary, Watson))) Thanks a lot!Subsidy
The same conclusion I reached, but is it safe to make it strong? My constraint is in a collection view cell and I'm concerned that holding the strong ref will create a retain cycle when cells are recycled.Soubriquet
@Echelon, that can't be answered without knowing more about your class relationships. However, cycles are OK as long as there's a clear point where they are broken.Araiza
One solution could be to change the constant value of the constraint.Waterage
@Soubriquet I believe, yes, it is safe to make an NSAutolayoutConstraint strong. It's my understanding that NSAutolayoutConstraint itself has weak references to the elements that it constrains, so there is no possibility of a cycle. I'm happy to be corrected on this though! It seems like a question that could be resolved with a fairly simple unit test. Create two views. Create a strong constraint on them. Release your strong references on the views. Check if a weak reference on the views still reaches them. If it does, the constraint is holding them, otherwise, it's not.Phocomelia
#27495042 It's working with clear explanation.Davis
C
21

A possible workaround would be to change the constraint priority instead of making it inactive:

@property (nonatomic, weak) IBOutlet NSLayoutConstraint* leftConstraint;
(...)
self.leftConstraint.priority = 250;

Then, self.leftConstraint is not disposed.

EDIT:

Xcode does not support changing priority for required (=1000) constraints, so be sure you switch in a range between 1...999.

Cutlip answered 29/9, 2017 at 10:34 Comment(0)
R
8

First change the IBOutlet variable to an optional. ie:

from :

@IBOutlet weak var myConstraint : NSLayoutConstraint!

to:

@IBOutlet weak var myConstraint : NSLayoutConstraint?

Now, to make it easier to manage/change from the storyboard in the future, add a new variable (eg myConstraint_DefualtValue) and set this to the value of myConstraint in viewDidLoad

var myConstraint_DefualtValue = CGFloat(0)
override func viewDidLoad() {
    super.viewDidLoad()

    self.myConstraint_DefualtValue = self.myConstraint.constant

}

I assume it is obvious why you need to set it in viewDidLoad and not somewhere else

Then when you want to deactivate it:

self.myConstraint?.isActive = false

And when you want to reactivate it (assuming you have the view as an outlet(myViewThatHasTheConstraint) and the constraint is a height constraint):

self.myConstraint = self.myViewThatHasTheConstraint.heightAnchor.constraint(equalToConstant: self.myConstraint_DefualtValue);
self.myConstraint?.isActive = true
Responser answered 24/7, 2018 at 13:34 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.