我很欣赏XCode将捕获不可解决的NSLayoutConstraints
并提供有关它的一些信息,但是我不知道如何获取控件/约束的内存地址并将其映射到有问题的实际控件。
我的应用程序相当大(大约20个屏幕),有些是大型UIViewControllers,其中包含多个子视图控制器。一些是带有自定义单元格的UITableViews和带有自定义单元格的UICollectionViews。我有一段时间来解决这个错误的原因(在横向旋转时发生)
以下是我的控制台提供的信息:
2013-05-02 11:18:53.225 Smile[7519:c07] 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)
(
"<NSAutoresizingMaskLayoutConstraint:0x16083b60 h=-&- v=-&- UIView:0xa5a1d00.width == UIWindow:0xa09eee0.width>",
"<NSLayoutConstraint:0xa5a2180 V:[UIView:0xa59f160]-(954)-| (Names: '|':UIView:0xa5a1d00 )>",
"<NSLayoutConstraint:0xa5a2140 V:|-(0)-[UIView:0xa59f160] (Names: '|':UIView:0xa5a1d00 )>",
"<NSAutoresizingMaskLayoutConstraint:0xa593340 h=--- v=--- H:[UIWindow:0xa09eee0(768)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0xa5a2180 V:[UIView:0xa59f160]-(954)-| (Names: '|':UIView:0xa5a1d00 )>
Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
如您所见,列出了内存地址。将它们粘贴到观察窗口的搜索栏中并没有太多显示。通过线程和队列调用堆栈进行筛选,我只在此断点上获得反汇编代码(异常断点)。
答案 0 :(得分:7)
由于这些网站我发现了一种解决方案:Debugging iOS AutoLayout Issues和Dancing with the Debugger。感谢Xcode控制台,您可以确定问题来自哪个视图。
解决方案:
第1步:
UIViewAlertForUnsatisfiableConstraints
第2步:运行您的项目。当控制台打印Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7fc82d3e18a0 H:[UIView:0x7fc82aba1210(768)]>
时,请复制视图的内存地址(此处为0x7fc82aba1210
)。
步骤3:在控制台中使用此命令更改此视图的背景以了解它是哪一个:e (void)[0x7fc82d3e18a0 setBackgroundColor:[UIColor redColor]]
步骤4:继续该程序并查看更新的UI。红色背景颜色的视图是有问题的视图。
步骤5:返回您的IB并查找此视图中存在问题的约束。
答案 1 :(得分:4)
简短的答案并非如此,OS X有一个标识符属性,可以在NSLayoutConstraint用来帮助识别视图但在iOS上不存在的视图上设置。
然而,有一种“解决方法”在iOS上实现类似的东西,但它并不漂亮。首先,您必须为每个视图建立一个名称,这在UIView类别中完成。然后,您必须更新NSLayoutConstraint描述的输出以使用新标记。
@interface NSLayoutConstraint (Nametags)
- (NSString *)asciiArtDescription;
@end
@interface UIView (Nametags)
@property (nonatomic, strong) NSString *nametag;
@end
然后提供如下实现来更改NSLayout的输出
#import <objc/objc-runtime.h>
static const char nametag_key;
@implementation NSLayoutConstraint (Nametags)
- (NSString *)description {
NSMutableString *myDescription = [NSMutableString stringWithFormat:@"%@, ", [self asciiArtDescription]];
UIView *firstView = (UIView *)[self firstItem];
if (firstView) {
[myDescription appendFormat:@"First View: 0x%0x: %@, ", (int)firstView, firstView.nametag];
}
UIView *secondView = (UIView *)[self secondItem];
if (secondView) {
[myDescription appendFormat:@"Second View: 0x%0x: %@", (int)secondView, secondView.nametag];
}
return myDescription;
}
@end
@implementation UIView (Nametags)
- (id) nametag {
return objc_getAssociatedObject(self, (void *) &nametag_key);
}
- (void)setNametag:(NSString *) theNametag {
objc_setAssociatedObject(self, (void *) &nametag_key, theNametag, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
然后您就可以在视图上设置名称
了self.view.nametag = @"MyUsefulName";
或者在IB中定义它们
最后,当您转储约束时,您将获得您在输出中提供的名称。
"V:|-(202)-[UIView:0x75606f0], First View: 0x75606f0: Blue View, Second View: 0x7560bd0: (null)",
"V:[UIView:0x75606f0]-(72)-|, First View: 0x7560bd0: (null), Second View: 0x75606f0: Blue View",
"V:[UIView:0x7560bd0(548)], First View: 0x7560bd0: (null), "
您应该只在调试版本中使用此代码,不要在应用程序中发送它,因为它访问私有[NSLayoutConstraint asciiArtDescription]方法。
答案 2 :(得分:0)
您可以尝试使用visualizeConstraints:
,如上所述here,看看您是否可以找到不良约束。