Why am I getting a “Auto Layout still required after executing -layoutSubviews” error every time my app launches now?

前端 未结 9 793
盖世英雄少女心
盖世英雄少女心 2020-12-11 01:11

Since I added the following code, every time my app opens this UITableViewController it crashes:

 self.noArticlesView = [[UIView alloc] init];
          


        
相关标签:
9条回答
  • 2020-12-11 01:33

    A possible solution is not to add the noArticlesView directly in the table, but is to put the UITableView inside a container UIView (eventually setting table constraints to fit with the container frame) and then constraint your noArticlesView to the container, using the same constraints you set and in the same place in your code, that is inside the -tableView:numberOfRowsInSection: UITableViewDataSource method. I tested it with a simple example, and it worked.
    The changes you need to apply to your code are to replace the UITableViewController with a UIViewController, add a container view (unless you want your table to fit exactly with the view controller's view, in such case this view is the container) and then constraint your noArticleView to the container instead of the table. My example code is at the bottom of this answer.
    I will try to make a possible explanation of the reason of the issue and why this solution works, but consider that part of my explanation is based on guesses so it couldn't be completely exact.
    First of all a brief explanation of how the view hierarchy rendering process works in iOS. The first step for the layout engine is to determine the size and position of all views and subviews in the view hierarchy. Usually this is done with an iterative approach, where auto layout constraints are evaluated, in order to determine size and position of views and subviews, and then each view's -layoutSubviews method is called for fine tuning: this means that you can change your layout after constraints are evaluated. What the layout engine requires is that if the -layoutSubviews method changes constraints again, then -[super layoutSubviews] must be called again to allow the iterative process: if this doesn't happen the layout engine raises an exception. In the case of the UITableView my guess is that the tableView:numberOfRowsInSection: method is called somewhere within the internal UITableView layoutSubviews method and this method doesn't call [super layoutSubviews]. So if your table data source method updates internal table constraints, at the end of the method the exception is triggered. The solution I propose works because the only constraint applied to the table is the external constraint towards the container, so evaluated at the first stage of the layout process, while the constraints added in the table data source method are not relevant to the table as they are applied to views external to the table (container and noArticlesView) so they don't affect the internal table view layout process.

    
    
    //
    //  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)
  • 2020-12-11 01:36

    You can add your 'no articles view' as a custom header in the table to make sure it's positioned correctly.

    0 讨论(0)
  • 2020-12-11 01:38

    You also need to disable mask translation for the table view.

    0 讨论(0)
提交回复
热议问题