2

这个实在是太诡异了。这是错误:

***** 由于未捕获的异常“NSGenericException”而终止应用程序,原因:“无法在视图上安装约束。约束是否引用了视图子树之外的内容?那是违法的。约束:视图:>'**

所以我的自定义单元格有一个子视图,我是在配置步骤中添加的。也就是说,我 deuque 一个单元格,然后使用数据对象对其进行配置。在配置步骤中,如果不存在,则添加第三方子视图:

if (!self.thirdPartyAnswerView) {
    self.thirdPartyAnswerView = [TCThirdPartyAPIHelper thirdPartyAnswerViewForThirdPartyAPIServiceType:answer.thirdPartyObject.thirdPartyAPIType];
    self.thirdPartyAnswerView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.contentWrapperView addSubview:self.thirdPartyAnswerView];
    NSDictionary *metrics = @{
                              @"TC_CELL_TOP_PADDING": [NSNumber numberWithFloat:TC_CELL_TOP_PADDING],
                              @"TC_CELL_BOTTOM_PADDING": [NSNumber numberWithFloat:TC_CELL_BOTTOM_PADDING],
                              @"TC_CELL_RIGHT_PADDING": [NSNumber numberWithFloat:TC_CELL_RIGHT_PADDING],
                              @"TC_CELL_LEFT_PADDING": [NSNumber numberWithFloat:TC_CELL_LEFT_PADDING],
                              };
    [self.contentWrapperView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-TC_CELL_LEFT_PADDING-[_thirdPartyAnswerView]-TC_CELL_RIGHT_PADDING-|" options:0 metrics:metrics views:NSDictionaryOfVariableBindings(_thirdPartyAnswerView)]];
    [self.contentWrapperView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-TC_CELL_TOP_PADDING-[_thirdPartyAnswerView]-TC_CELL_BOTTOM_PADDING-|" options:0 metrics:metrics views:NSDictionaryOfVariableBindings(_thirdPartyAnswerView)]];
}

这一切都很好。事实上,它工作得很好。我步入我的答案单元格(呈现模态编辑/创建流程),然后完成并返回同一屏幕。我用动画很好地更新了行,而不是调用reloadData.

屏幕

当我在拥有现有数据后点击类别按钮时,问题就出现了。它拉出一个类别选择模式。当我选择一个类别时,它reloadData会在前一个屏幕中调用,然后将类别模式动画化。好吧,至少这是它应该做的。相反,它会在动画开始时立即崩溃。它调用reloadData没有问题,但动画一开始,就轰隆隆。它要么抛出我上面显示的崩溃,不提供任何解释,要么崩溃并抱怨_supportsContentDimensionVariables选择器被发送到错误的对象。

由于使用的视图可能因单元格而异,因此在调用中prepareForReuse我删除了thirdPartyAnswerView. 如果我删除它,它不会崩溃(但是我的单元格中有一个我不想要的视图)。我尝试在前后删除约束:

if (self.thirdPartyAnswerView) {
    [self.contentWrapperView removeConstraints:self.thirdPartyAnswerView.constraints];
    [self.thirdPartyAnswerView removeFromSuperview];
    self.thirdPartyAnswerView = nil;
}

那没有用。我尝试将这些东西移出prepareForReuse并移入配置部分(在添加新子视图之前删除子视图)。那没有用。我不知所措。

更新

以下是选择模式中的类别时调用的代码:

categorySelectionVC.didTouchCategoryBlock = ^(TCCategory *category) {
    TCQuestionBuilderViewController *sself = weakself;
    sself.category = category;
    [sself.tableView reloadData];
    [sself.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:TableSectionCategory] animated:NO scrollPosition:UITableViewScrollPositionNone];
    [sself dismissViewControllerAnimated:YES completion:^{
    }];
};

我已经确定,如果我selectRowAtIndexPath在重新加载后注释掉该位,它就可以正常工作。我不明白为什么。我已经用过很多次了。我重新加载数据,重新选择选择的内容,以便在再次看到 tableView 时动画“关闭”。

我错了。虽然删除它最初确实解决了它,但如果您再次进入模式然后再次选择一个类别,它就会崩溃。

解决了

感谢 sapi,我发现约束没有被正确删除。使用constraints关闭的属性thirdPartyView不包括存储在父视图上的约束。不得不使用这种语法,虽然我猜有一个更短的方法来做到这一点:

for (NSLayoutConstraint *constraint in self.contentWrapperView.constraints) {
    if (constraint.firstItem == self.thirdPartyAnswerView || constraint.secondItem == self.thirdPartyAnswerView) {
        [constraints addObject:constraint];
    }
}
[self.contentWrapperView removeConstraints:constraints];
4

1 回答 1

2

约束是双向的,但反向关系由与正向关系不同的对象表示。

例如,如果您使用以下命令创建约束:

[self.contentWrapperView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-TC_CELL_LEFT_PADDING-[_thirdPartyAnswerView]-TC_CELL_RIGHT_PADDING-|" options:0 metrics:metrics views:NSDictionaryOfVariableBindings(_thirdPartyAnswerView)]];

thenself.contentWrapperView_thirdPartyAnswerView两者都添加了约束,但是虽然它们都表示相同的关系,但它们是不同的对象

你打电话时:

[self.contentWrapperView removeConstraints:self.thirdPartyAnswerView.constraints];

这试图删除与 上的相同的self.contentWrapperView所有约束self.thirdPartyAnswerView,即没有。

要删除适当的约束,您必须遍历数组并识别引用的那些thirdPartyAnswerView(有关执行此操作的一种方法,请参阅问题编辑)。

于 2013-03-27T21:54:22.990 回答