为什么我将弱IBOutlet NSLayoutConstraint设置为非活动状态时会变成nil?

51

我的应用程序中有一个IBOutlet NSLayoutConstraint。非常简单:

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

我想在某个时候停用这个约束:

self.leftConstraint.active = NO;

这种情况发生在从 cellForRowAtIndexPath: 调用的方法中。在上述代码行之后,约束变成了 nil。但是,如果我将此属性声明为 strong,那么就不会出现这种情况,它不会变成 nil。有人能解释一下为什么会这样吗?

3个回答

101

当视图的constraints属性是唯一strong引用时,如果你的输出口是weak类型的话。通过停用约束条件可以将其从数组中删除,这样就不会再有strong类型的引用了。


初学者,Watson))) 非常感谢! - Andrey Chernukha
4
我得出了相同的结论,但加强它是否安全?我的限制在于集合视图单元格中,我担心保留强引用会在重复使用单元格时创建保留循环。 - Echelon
@Echelon,没有更多关于你的类关系的信息,无法回答这个问题。然而,只要在明确的中断点上打破它们,循环就没问题。 - Avi
一个解决方案可能是改变约束的“常量”值。 - Manish Singh
1
@Echelon 我相信,是的,将NSAutolayoutConstraint设置为strong是安全的。据我了解,NSAutolayoutConstraint本身对其约束的元素具有weak引用,因此不存在循环引用的可能性。不过如果有错误,请指正!这似乎是一个可以通过简单的单元测试来解决的问题。创建两个视图。在它们之间创建一个强约束。释放视图上的强引用。检查视图上的弱引用是否仍然能够访问它们。如果可以,则该约束确实将它们保持在一起,否则就没有。 - Benjohn
这个链接提供了一个清晰的解释,可以帮助你了解何时可以激活或取消布局约束。 - Lokesh

21

一个可能的解决方法是改变约束优先级而不是使其无效:

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

那么,self.leftConstraint 没有被释放。

编辑:

Xcode 不支持更改必需的(=1000)约束的优先级,因此请确保在1...999范围内切换。


8

首先,将IBOutlet变量更改为可选类型。例如:

原代码:

@IBOutlet weak var myConstraint : NSLayoutConstraint!

to:

@IBOutlet weak var myConstraint : NSLayoutConstraint?

现在,为了将来更容易地从Storyboard进行管理/更改,请添加一个新变量(例如 myConstraint_DefualtValue ),并在 viewDidLoad 中将其设置为 myConstraint 的值。
var myConstraint_DefualtValue = CGFloat(0)
override func viewDidLoad() {
    super.viewDidLoad()

    self.myConstraint_DefualtValue = self.myConstraint.constant

}

我假设你已经明白为什么需要在viewDidLoad中设置它,而不是其他地方。然后,当你想要停用它时:
self.myConstraint?.isActive = false

当您想重新激活它时(假设您已将视图作为出口(myViewThatHasTheConstraint)并且约束是一个高度约束):

self.myConstraint = self.myViewThatHasTheConstraint.heightAnchor.constraint(equalToConstant: self.myConstraint_DefualtValue);
self.myConstraint?.isActive = true

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接