NSLayoutConstraint 的幽灵困扰着我的视图层次结构?

The ghost of NSLayoutConstraint haunts my view hierarchy?

我正在尝试以编程方式修改自动布局约束以向上移动 table 视图,但仅适用于横向模式下的 iPhone 6 Plus,因为我无法获得精确的视觉效果我希望在所有设备上使用 Xcode 6.2 beta 3 Interface Builder 的自动布局(从 IB 获得其他支持的 devices/orientations。只是 iPhone 6 Plus 有点离群iPhone 和 iPad,因此有点棘手)

我删除的一个约束似乎在删除后被删除(例如,如预期的那样从包含视图的约束中消失),但是,布局管理器仍然 似乎找到它并警告它与其他约束冲突并在运行时打破约束,幸运的是应用程序产生了预期的视觉结果,但不幸的是丑陋的控制台警告消息的副作用,我想修复它,因为它很丑陋,Apple 文档将此类警告归咎于用户代码错误。

我的代码拦截方向变化(仅在 iPhone 6 Plus 上), 然后:

=============

• 在table视图的所有者视图

中迭代约束

• 打印具有 .Top

属性的任何约束的属性

• 删除通过 IBOutlet 引用的中心 Y 约束,用于 table 视图

• 删除具有 .Top 属性的约束

• 添加具有 不同 乘数

的新 .Top 属性

============

这是我的视图控制器中的 swift 代码:

    override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
        switch(toInterfaceOrientation) {
        case .LandscapeLeft:
            fallthrough
        case .LandscapeRight:
            var deviceType = UIDevice().deviceType

            if (deviceType == .iPhone6plus || deviceType == .simulator) {
                if centerYconstraint != nil {
                    self.view.removeConstraint(centerYconstraint)
                    centerYconstraint = nil
                    for constraint in self.view.constraints() {
                        if (constraint.firstItem as NSObject == self.tableView) {
                            if (constraint.firstAttribute == NSLayoutAttribute.Top) {
                                println("found item \(constraint)")
                                let view1 = constraint.firstItem as UIView
                                let attr1 = constraint.firstAttribute
                                let view2 = constraint.secondItem as UIView
                                let attr2 = constraint.secondAttribute
                                let relation = constraint.relation
                                let constant = constraint.constant
                                let newConstraint = NSLayoutConstraint(
                                    item:       view1,
                                    attribute:  attr1,
                                    relatedBy:  relation,
                                    toItem:     view2,
                                    attribute:  attr2,
                                    multiplier: 0.02,
                                    constant:   constant)
                                self.view.removeConstraint(constraint as NSLayoutConstraint)
                                self.view.addConstraint(newConstraint)
                                self.view.layoutIfNeeded()
                            }
                        }
                    }
                }
            }
        default:
            break
        }
    }

这是 Xcode 模拟器的输出。请注意第一行 "found item",我在其中打印了我删除的约束。

但是您可以在布局管理器随后抱怨的潜在冲突列表中看到 相同 view1 和 view2、乘法器和属性。这就是我困惑的地方。

found item <NSLayoutConstraint:0x7f8a05101bb0 UITableView:0x7f8a05853000.top == 0.03*_UILayoutGuide:0x7f8a035517e0.top>


2015-01-03 14:36:35.290 Interphase[46388:74323123] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x7f8a0354da40 V:[UITableView:0x7f8a05853000(336)]>",
    "<_UILayoutSupportConstraint:0x7f8a0514df70 V:[_UILayoutGuide:0x7f8a035517e0(49)]>",
    "<_UILayoutSupportConstraint:0x7f8a051908e0 _UILayoutGuide:0x7f8a035517e0.bottom == UIView:0x7f8a03551480.bottom>",
    "<NSLayoutConstraint:0x7f8a051b53d0 'UIView-Encapsulated-Layout-Height' V:[UIView:0x7f8a03551480(414)]>",
    "<NSLayoutConstraint:0x7f8a050d9080 UITableView:0x7f8a05853000.top == 0.02*_UILayoutGuide:0x7f8a035517e0.top>",
    "<NSLayoutConstraint:0x7f8a0354ef80 UITableView:0x7f8a05853000.centerY == UIView:0x7f8a03551480.centerY>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7f8a0354da40 V:[UITableView:0x7f8a05853000(336)]>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2015-01-03 14:36:56.720 Interphase[46388:74323123] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<_UILayoutSupportConstraint:0x7f8a0514df70 V:[_UILayoutGuide:0x7f8a035517e0(49)]>",
    "<_UILayoutSupportConstraint:0x7f8a051908e0 _UILayoutGuide:0x7f8a035517e0.bottom == UIView:0x7f8a03551480.bottom>",
    "<NSLayoutConstraint:0x7f8a05101bb0 UITableView:0x7f8a05853000.top == 0.03*_UILayoutGuide:0x7f8a035517e0.top>",
    "<NSLayoutConstraint:0x7f8a051b53d0 'UIView-Encapsulated-Layout-Height' V:[UIView:0x7f8a03551480(736)]>",
    "<NSLayoutConstraint:0x7f8a050d9080 UITableView:0x7f8a05853000.top == 0.02*_UILayoutGuide:0x7f8a035517e0.top>"
)

向视图添加和删除约束有点不稳定。从来没有完全清楚应该将它们添加到哪个视图,然后当您想要删除它时很难找到它。

更好的解决方案是保留对您关心的约束的引用(如果您是从界面构建器中执行的,则作为出口,或者只是将它们存储在属性中),然后 activate或根据需要停用它们。

激活约束而不是添加它们还可以避免您必须决定将它们添加到哪个视图是合适的 - 系统会自动执行此操作。