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

时间:2013-11-07 13:22:07

标签: ios objective-c uitableview autolayout nslayoutconstraint

由于我添加了以下代码,因此每次我的应用打开此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]];    

它给了我这个错误:

  

* 由于未捕获的异常终止应用' NSInternalInconsistencyException',原因:'执行-layoutSubviews后仍需要自动布局。 UITableView&-outoutSubviews的实现需要调用super。'

我到底在做什么?当有0行时,我在tableView:numberOfRowsInSection:中调用该代码。

9 个答案:

答案 0 :(得分:14)

我是UIScrollView的子类,并在iOS 7上收到了相同的错误消息(但不是8)。

我以类似于以下的方式覆盖layoutSubviews:

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

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

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

答案 1 :(得分:2)

有同样的问题。添加了对self.tableView和使用的约束的视图。不要通过addSubview将视图添加到表视图中:但是将它们添加为页眉,页脚或单元格。

答案 2 :(得分:2)

[self.view layoutIfNeeded]

希望这有帮助

答案 3 :(得分:1)

您还需要禁用表格视图的掩码转换。

答案 4 :(得分: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];
}

答案 5 :(得分:0)

结帐"Auto Layout still required after executing -layoutSubviews" with UITableViewCell subclass,因为问题似乎相同。

我能够实现one of the answers中提到的类别,为我解决了这个问题。但是,我必须在UITableView类而不是UITableViewCell类上创建类别,如特定答案中所讨论的那样。

答案 6 :(得分:0)

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

答案 7 :(得分:0)

一种可能的解决方案是不直接在表中添加noArticlesView,而是将UITableView放在容器UIView内(最终设置表约束以适应容器框架) )然后使用您设置的相同约束以及代码中位于noArticlesView -tableView:numberOfRowsInSection:方法内的相同位置,将UITableViewDataSource约束到容器。 我用一个简单的例子测试了它,它起作用了。
您需要应用于代码的更改是用UIViewController替换UITableViewController,添加容器视图(除非您希望表与视图控制器的视图完全匹配,在这种情况下,此视图是容器)然后将noArticleView约束到容器而不是表。 我的示例代码位于此答案的底部。
我将尽力解释问题的原因以及解决方案的原因,但请考虑我的解释部分是基于猜测,因此不能完全准确。
首先简要说明视图层次结构渲染过程在iOS中的工作原理。布局引擎的第一步是确定视图层次结构中所有视图和子视图的大小和位置。通常这是通过迭代方法完成的,其中评估自动布局约束,以确定视图和子视图的大小和位置,然后调用每个视图的 -layoutSubviews方法进行微调:这意味着您可以更改评估约束后的布局。布局引擎需要的是,如果-layoutSubviews方法再次更改约束,则必须再次调用-[super layoutSubviews]以允许迭代过程:如果不发生这种情况,则布局引擎会引发异常。在UITableView的情况下,我的猜测是在内部UITableView layoutSubviews方法中的某处调用tableView:numberOfRowsInSection:方法,并且此方法不调用[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;
}

答案 8 :(得分:-8)

我取消选中了视图控制器上的自动布局,现在没有发生崩溃