感谢http://useYourLoaf.com提供完整的解决方案:
http://useyourloaf.com/blog/using-identifiers-to-debug-autolayout.html
我在 WWDC 2015 的 Auto Layout 会议中发现了一个快速提示,有助于调试约束问题
如果您使用过 Auto Layout,您将熟悉 Xcode 在出错时吐出的日志。为了创建一个示例,我修改了 Stack View 示例代码,并为每个图像添加了一个约束,为它们提供了 240 的固定宽度(我们将看到这不是一个好主意)。
这适用于 iPad 等常规宽度视图,但对于紧凑宽度视图(如 iPhone 纵向视图)来说太宽了。运行时的控制台日志读起来并不有趣。跳过样板文本,您将获得有问题的约束的列表:
"<NSLayoutConstraint:0x7fc1ab520360 H:[UIImageView:0x7fc1ab532650(240)]>",
"<NSLayoutConstraint:0x7fc1ab536ef0 H:[UIImageView:0x7fc1ab537380(240)]>",
"<NSLayoutConstraint:0x7fc1ab545cc0 UIView:0x7fc1ab53d870.trailingMargin == UIStackView:0x7fc1ab53dae0.trailing>",
"<NSLayoutConstraint:0x7fc1ab545d10 UIStackView:0x7fc1ab53dae0.leading == UIView:0x7fc1ab53d870.leadingMargin>",
"<NSLayoutConstraint:0x7fc1ab54e240 'UISV-alignment' UIStackView:0x7fc1ab53dc70.centerX == UIStackView:0x7fc1ab531a10.centerX>",
"<NSLayoutConstraint:0x7fc1ab5167c0 'UISV-canvas-connection' UIStackView:0x7fc1ab531a10.leading == UIImageView:0x7fc1ab532650.leading>",
"<NSLayoutConstraint:0x7fc1ab54ad80 'UISV-canvas-connection' H:[UIImageView:0x7fc1ab537380]-(0)-| (Names: '|':UIStackView:0x7fc1ab531a10 )>",
"<NSLayoutConstraint:0x7fc1ab5397d0 'UISV-canvas-connection' UIStackView:0x7fc1ab53dae0.leading == _UILayoutSpacer:0x7fc1ab54c3c0'UISV-alignment-spanner'.leading>",
"<NSLayoutConstraint:0x7fc1ab54a4a0 'UISV-canvas-connection' UIStackView:0x7fc1ab53dae0.centerX == UIStackView:0x7fc1ab53dc70.centerX>",
"<NSLayoutConstraint:0x7fc1ab54b110 'UISV-spacing' H:[UIImageView:0x7fc1ab532650]-(16)-[UIImageView:0x7fc1ab537380]>",
"<NSLayoutConstraint:0x7fc1ab548210 'UISV-spanning-boundary' _UILayoutSpacer:0x7fc1ab54c3c0'UISV-alignment-spanner'.leading <= UIStackView:0x7fc1ab531a10.leading>",
"<NSLayoutConstraint:0x7fc1ab551690 'UIView-Encapsulated-Layout-Width' H:[UIView:0x7fc1ab53d870(375)]>"
然后,日志会告诉您它已决定打破上述哪些限制:
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7fc1ab536ef0 H:[UIImageView:0x7fc1ab537380(240)]>
日志输出使用自动布局视觉格式语言,但很难从系统创建的约束中挑选出我的约束。对于堆栈视图尤其如此,堆栈视图的设计旨在为您创建大部分约束。在这个简单的例子中,我知道我刚刚添加的固定宽度约束破坏了一些东西,但是从日志中很难看出这一点,而且视图越复杂,就越难。
将标识符添加到约束
NSLayoutConstraint
如果您为每个约束添加一个标识符(自 iOS 7 以来就有一个标识符属性),那么日志会更容易理解。在 Interface Builder 中找到约束并在属性检查器中添加标识符(我使用 $ 作为前缀/后缀以使它们在日志中脱颖而出):
2015 年 8 月 18 日更新:正如评论中所指出的,标识符只能在从 Xcode 7 开始的 Interface Builder 中编辑。它在 Xcode 6.4 中不可见。
如果在代码中添加约束:
constraint.identifier = "$HeartImageFixedWidth$"
如果您使用的是使用约束数组的视觉格式语言,那就更棘手了。例如,考虑为心脏图像视图创建固定宽度约束的 Swift 代码片段:
let heartWidth = NSLayoutConstraint.constraintsWithVisualFormat("[heart(240)]",
options:[], metrics:nil, views:viewsDictionary)
由于 heartWidth 是 [NSLayoutConstraint] 类型的数组,因此设置标识符需要做更多的工作:
for constraint in heartWidth {
constraint.identifier = "$HeartImageFixedWidth$"
}
heartImage.addConstraints(heartWidth)
为我的约束设置标识后,现在可以更轻松地在日志文件中找到它们(参见前四行):
"<NSLayoutConstraint:0x7f92a305aeb0 '$ContainerStackViewLeading$' UIStackView:0x7f92a3053220.leading == UIView:0x7f92a3052fb0.leadingMargin + 32>",
"<NSLayoutConstraint:0x7f92a305b340 '$ContainerStackViewTrailing$' UIView:0x7f92a3052fb0.trailingMargin == UIStackView:0x7f92a3053220.trailing + 32>",
"<NSLayoutConstraint:0x7f92a301cf20 '$HeartImageFixedWidth$' H:[UIImageView:0x7f92a3047ef0(240)]>",
"<NSLayoutConstraint:0x7f92a3009be0 '$StarImageFixedWidth$' H:[UIImageView:0x7f92a304d190(240)]>",
"<NSLayoutConstraint:0x7f92a3060cc0 'UISV-alignment' UIStackView:0x7f92a30533b0.centerX == UIStackView:0x7f92a30472b0.centerX>",
"<NSLayoutConstraint:0x7f92a301c590 'UISV-canvas-connection' UIStackView:0x7f92a30472b0.leading == UIImageView:0x7f92a3047ef0.leading>",
"<NSLayoutConstraint:0x7f92a305f680 'UISV-canvas-connection' H:[UIImageView:0x7f92a304d190]-(0)-| (Names: '|':UIStackView:0x7f92a30472b0 )>",
"<NSLayoutConstraint:0x7f92a3064190 'UISV-canvas-connection' UIStackView:0x7f92a3053220.leading == _UILayoutSpacer:0x7f92a30608a0'UISV-alignment-spanner'.leading>",
"<NSLayoutConstraint:0x7f92a30415d0 'UISV-canvas-connection' UIStackView:0x7f92a3053220.centerX == UIStackView:0x7f92a30533b0.centerX>",
"<NSLayoutConstraint:0x7f92a305fa10 'UISV-spacing' H:[UIImageView:0x7f92a3047ef0]-(16)-[UIImageView:0x7f92a304d190]>",
"<NSLayoutConstraint:0x7f92a30508c0 'UISV-spanning-boundary' _UILayoutSpacer:0x7f92a30608a0'UISV-alignment-spanner'.leading <= UIStackView:0x7f92a30472b0.leading>",
"<NSLayoutConstraint:0x7f92a3063240 'UIView-Encapsulated-Layout-Width' H:[UIView:0x7f92a3052fb0(375)]>"
它也更清楚系统选择打破哪些约束:
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7f92a3009be0 '$StarImageFixedWidth$' H:[UIImageView:0x7f92a304d190(240)]>
将标识符添加到约束并非不费吹灰之力,但它可以在您下次必须对复杂布局的调试日志进行排序时得到回报。
延伸阅读