NSGenericException', reason: '无法在视图上安装约束条件

31

因未捕获的异常 'NSGenericException' 而终止应用程序,原因是:无法在视图上安装约束条件。 约束条件是否引用视图子树之外的内容? 这是不合法的。 约束条件为: 视图:;层 = ;contentOffset: {0, 0}>'


请在此处放置代码以获得更好的理解。 - iPatel
你在哪个操作系统版本中遇到了这个错误? - Crazy Developer
我猜你可能需要详细阐述你的问题,或者贴上你的代码以获得更有帮助的答案。 - ipmcc
7个回答

53

您需要将限制条件安装在两个视图中“更高的”一个上。一种好的一般方法是这样的:

NSLayoutConstraint* constraint = ...;
NSView* firstView = constraint.firstItem;
NSView* secondView = constraint.secondItem;    
[[firstView ancestorSharedWithView: secondView] addConstraint: constraint];

仅提醒一下:要记住约束属性是在添加它们的视图上下文中进行评估的。因此,例如,对于安装在viewB上的约束的viewA的NSLayoutAttributeLeft的值在viewB的坐标空间中解释。对于仅参考兄弟视图或其父视图的约束,这个事实基本上不相关,但并没有限制约束不能引用不是兄弟或直接父级的两个视图。


在我的应用程序中,我使用日期选择器,在选择日期后导航到下一个视图,当我返回到此视图控制器时,应用程序崩溃并生成上述错误...... - adevani11
这个 ancestorSharedWithView 方法只在 Mac 上定义了,而没有在 iOS 上定义吗?我看到它是在 AppKit.framework 库中定义的,而这个库只属于 Mac OSX10.8。 - abbood
哦,确实在UIView上似乎没有相应的方法,这有点儿傻。编写这样一个方法是相当简单的 - 只需沿着firstView的层次结构向上遍历,并在每一步询问[secondView isDescendantOfView: x]。但概念是相同的 - 您始终希望在所有涉及视图的共同祖先上安装约束,并且该约束将在安装它的视图的坐标空间中解决。 - ipmcc

11

和neoneye一样,我因为移除带有约束条件的子视图而出现了这个问题。但是,我有一个将父视图定位的约束条件,如果我调用[self.view removeConstraints:self.view.constraints];就会将其删除。相反,我进行了以下更改:

原始代码:

for (UIView *subview in [view subviews]) {
    [subview removeFromSuperview];
}

已修复以消除子视图上的约束限制:

NSMutableArray * constraints_to_remove = [ @[] mutableCopy] ;
for( NSLayoutConstraint * constraint in view.constraints) {
    if( [view.subviews containsObject:constraint.firstItem] ||
       [view.subviews containsObject:constraint.secondItem] ) {
        [constraints_to_remove addObject:constraint];
    }
}
[view removeConstraints:constraints_to_remove];

for (UIView *subview in [view subviews]) {
    [subview removeFromSuperview];
}

更新:所以我再次遇到了这个错误 - 这次是由于移除一个视图导致的。添加了一个函数来清理地删除该视图:

void cleanRemoveFromSuperview( UIView * view ) {
  if(!view || !view.superview) return;

  //First remove any constraints on the superview
  NSMutableArray * constraints_to_remove = [NSMutableArray new];
  UIView * superview = view.superview;

  for( NSLayoutConstraint * constraint in superview.constraints) {
    if( constraint.firstItem == view ||constraint.secondItem == view ) {
      [constraints_to_remove addObject:constraint];
    }
  }
  [superview removeConstraints:constraints_to_remove];

  //Then remove the view itself.
  [view removeFromSuperview];
}

4
我在iOS6上遇到了这个错误。在我的情况下,是因为我在删除约束之前先删除了子视图。
// I had forgotten to remove constraints first. This caused the crash.
[self.view removeConstraints:self.view.constraints];

NSArray *subviews = self.view.subviews;
for (UIView *subview in subviews) {
    [subview removeFromSuperview];
}

[self addYourSubviewsHere];

这段代码的问题在于它将删除self.view的所有约束,而不仅仅是与你要删除的子视图相关的约束... - nduplessis

2

我遇到了一个问题,使用UIPickerView作为UITextField的输入(使用Autolayout)。当我推出另一个视图控制器并返回到带有picker的视图控制器时,应用程序会崩溃。我在UIPickerViewController中找到了以下解决方案:

-(void)viewWillAppear:(BOOL)animated{

    [self.pickerView removeFromSuperview];
    [self.pickerView setTranslateAutoresizingMaskIntoContraints:YES];
    [self.view addSubview];

}   

在从父视图中移除后,您还可以设置UIPickerViewPosition。希望这能帮到您!


我有一个相同的问题,即使用UIDatePicker作为TextFieldinputAccessoryView。我推出了一个视图控制器,然后返回,它就会抛出异常。我尝试了你的代码,但对我不起作用。请注意,我在故事板中有UIDatePicker(而非通过代码创建)。 - Geek
顺便说一下,这个问题是iOS7的一个bug,我认为它将在7.1版本中得到修复。iOS在许多与自动布局相关的事情上显示出了很多问题。我也在storyboard中使用pickerview,对我来说它很有效。您可以尝试在让viewController之前从superview中删除datepicker。或者您可以尝试在viewDidAppear或viewDidLayoutSubviews上使用此代码。希望它能帮助到您!感谢您的报告。 - Lucio Fonseca

0

我发现添加这一行代码可以解决Cocoa ScrollView的问题。

[scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];

我认为某些视图在运行时添加了约束,因此当您通过Objective-C添加自己的约束时会发生冲突,因此您需要禁用此行为...


0

0

同样的错误,在这里有不同的解决方案:

在添加新视图并忘记在界面构建器中关闭使用自动布局后,我在iOS 6启动我的应用程序时遇到了这个错误...我讨厌它没有标准设置来默认使用自动布局来创建新视图...


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