为什么我的应用程序每次启动时都会出现“执行-layoutSubviews后仍需要自动布局”错误?

18
自从我添加了以下代码后,每次打开这个 UITableViewController 时应用程序都会崩溃:
 self.noArticlesView = [[UIView alloc] init];
 self.noArticlesView.translatesAutoresizingMaskIntoConstraints = NO;
 self.noArticlesView.backgroundColor = [UIColor colorWithRed:0.961 green:0.961 blue:0.961 alpha:1];

 [self.view addSubview:self.noArticlesView];

 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.noArticlesView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]];
 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.noArticlesView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0]];
 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.noArticlesView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0.0]];
 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.noArticlesView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0 constant:0.0]];    

它给我这个错误:

* Terminating app due to uncaught exception 'NSInternalInconsistencyException',原因:在执行-layoutSubviews后仍需要自动布局。UITableView的-layoutSubviews实现需要调用super。

我到底做错了什么?我在tableView:numberOfRowsInSection:中调用了那段代码,当时还没有行。


1
虽然我不是专家,但我也遇到了这个问题。我认为这是因为UITableView实现了自己的layoutSubviews版本(或者其他类似于它的方法,这对于自动布局是必需的)。我提高了你的问题,因为我也想知道答案 :) - Tancrede Chazallet
是的,我可能得回去使用框架来完成这个(之前我就是这么做的),但使用自动布局会更好。 :/ - Doug Smith
1
我为此回到了框架,但是一旦所有内容都使用自动布局,这真的不太方便... - Tancrede Chazallet
self.view是一个表视图吗?而self.noArticlesView是一个视图,应该覆盖在上面,显示没有表格单元格吗? - Max MacLeod
好的,这一切都在UITableViewController子类中运行,所以我想self.view是一个表格视图。你关于self.noArticlesView的看法是正确的。 - Doug Smith
9个回答

14

我正在对UIScrollView进行子类化,并在iOS 7上收到了与iOS 8不同的错误消息。

我正在以以下方式重写layoutSubviews方法:

- (void)layoutSubviews {
    [super layoutSubviews];
    // code to scroll the view
}

我通过将调用super的layoutSubviews方法放到该方法的最后一件事情来解决了这个问题:

- (void)layoutSubviews {
    // code to scroll the view
    [super layoutSubviews];
}

我遇到了同样的问题。我的子类中的 -(void)layoutSubViews 会修改一些约束常数。在修改约束之前调用 [super layoutSubviews] 会在iOS7上崩溃(但不会在8上)。 - AechoLiu

2

[self.view layoutIfNeeded]

Hope this helps


3
请为您的方法添加更多细节,不要只写一句话。 谢谢您的回答。 - ivan.mylyanyk

2

我也遇到了同样的问题。我通过添加视图到self.tableView并使用约束解决了这个问题。请勿通过addSubview:将视图添加到表格视图中,而是将它们作为header(s),footer(s)或cells添加。


1
对我来说,它是这样的。
self.tableView.backgroundView = self.emptyView;

我改成了这个

    NSComparisonResult order = [[UIDevice currentDevice].systemVersion compare: @"8.0" options: NSNumericSearch];
if (order == NSOrderedSame || order == NSOrderedDescending) {
    // OS version >= 8.0
    self.tableView.backgroundView = self.emptyView;
}else{
    [self.tableView.backgroundView addSubview:self.emptyView];
}

1
你还需要禁用表格视图的遮罩翻译。

0
一种可能的解决方案是不直接在表格中添加noArticlesView,而是将UITableView放置在容器UIView中(最终设置表格约束以适应容器框架),然后使用相同的约束和代码中相同位置,在-tableView:numberOfRowsInSection: UITableViewDataSource方法中将noArticlesView约束到容器中。 我用一个简单的例子测试过,结果成功了。
您需要对代码进行的更改是用UIViewController替换UITableViewController,添加一个容器视图(除非您想让您的表格与视图控制器完全匹配,在这种情况下,此视图即为容器),然后将noArticleView约束到容器而不是表格。 我的示例代码在本答案底部。
我将尝试解释问题的原因以及此解决方案为什么有效,但请考虑我的部分解释是基于猜测的,因此可能不完全准确。
首先,简要说明iOS中视图层次结构呈现过程的工作方式。布局引擎的第一步是确定视图层次结构中所有视图和子视图的大小和位置。通常,这是通过迭代方法完成的,其中评估自动布局约束,以确定视图和子视图的大小和位置,然后为微调调用每个视图的-layoutSubviews方法:这意味着您可以在评估约束后更改布局。布局引擎所需的是,如果-layoutSubviews方法再次更改约束,则必须再次调用-[super layoutSubviews]以允许迭代过程:如果未发生此情况,则布局引擎会引发异常。在UITableView的情况下,我猜测tableView:numberOfRowsInSection:方法在内部UITableView layoutSubviews方法的某个地方被调用,而此方法不会调用[super layoutSubviews]。因此,如果您的表格数据源方法更新了内部表格约束,则在该方法末尾触发异常。我提出的解决方案之所以有效,是因为唯一应用于表格的约束是针对容器的外部约束,在布局过程的第一阶段进行评估,而添加到表格数据源方法中的约束与表格无关,因为它们应用于表格外部的视图(容器和noArticlesView),因此它们不会影响内部表视图布局过程。


//
//  RootController.h

#import 

@interface RootController : UIViewController

@property (nonatomic,strong) IBOutlet UITableView *table;
@property (nonatomic,strong) IBOutlet UIView *container;

@end

//
//  RootController.m


#import "RootController.h"

@implementation RootController

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.

    UIView *_v = [[UIView alloc] init];
    _v.backgroundColor=[UIColor redColor];
    _v.translatesAutoresizingMaskIntoConstraints=NO;

    [self.container addSubview:_v];
    NSLayoutConstraint *_c1 = [NSLayoutConstraint constraintWithItem:_v
                                                            attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.container attribute:NSLayoutAttributeTop multiplier:1.0 constant:20.0];
    NSLayoutConstraint *_c2 = [NSLayoutConstraint constraintWithItem:_v
                                                           attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.container attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-20.0];
    NSLayoutConstraint *_c3 = [NSLayoutConstraint constraintWithItem:_v
                                                           attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.container attribute:NSLayoutAttributeLeft multiplier:1.0 constant:20.0];
    NSLayoutConstraint *_c4 = [NSLayoutConstraint constraintWithItem:_v
                                                           attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.container attribute:NSLayoutAttributeRight multiplier:1.0 constant:-20.0];
    [self.container addConstraints:@[_c1,_c2,_c3,_c4]];

    return 0;
}

0

0

您可以将“无文章视图”添加为自定义标题,以确保其正确定位在表中。


-8

我在视图控制器上取消了自动布局,现在不会崩溃了。


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