4

I have a UITableView, with a header defined in UIBuilder. I was running into errors with autoresizing masks conflicting with my constraints, so I started poking around until I found the cause.

Unfortunately, fixing what appears to be the cause is causing a crash. When I programmatically turn off setTranslatesResizingMasks, the conflicting layout error doesn't occur (either because it's fixed, or because it never gets the chance to) and instead I get a crash:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. UITableView's implementation of -layoutSubviews needs to call super.'

I tried the suggestion from some other threads (like this one) about using method swizzling to 'patch' UITableViewCell (and I went ahead and did UITableVIew while I was at it), but it didn't help.

Edit:

Here's some sample code that can make it. Because I need to be able to mutate the view at run time, it has to be created via code, not storyboard.

Please note that if I add the table header in as it's own view, everything works fine; it's when I try to embed it as the table's header view that things start to blow up. I either turn the tableHeader view's translateAutoresizingMaskIntoConstraints off to avoid conflicts, or I get conflicts with my use of autolayout (the constraints it breaks cause some of my controls to mysteriously vanish).

self.palletTagField=[[UITextField alloc] init];
[self.palletTagField setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.palletTagField setDelegate:self];
[self.palletTagField setBorderStyle:UITextBorderStyleRoundedRect];

UIButton *addButton=[UIButton buttonWithType:UIButtonTypeContactAdd];
[addButton addTarget:self
              action:@selector(addPalletTagButtonPressed)
    forControlEvents:UIControlEventTouchUpInside];
[addButton setTranslatesAutoresizingMaskIntoConstraints:NO];

UIView *tableHeader=[[UIView alloc] init];
[tableHeader setTranslatesAutoresizingMaskIntoConstraints:NO];//Problem line
[tableHeader addSubview:self.palletTagField];
[tableHeader addSubview:addButton];
[tableHeader addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-[field]-[button]-|"
                                                                    options:NSLayoutFormatAlignAllCenterY
                                                                    metrics:nil
                                                                      views:@{@"field":self.palletTagField,
                                                                              @"button":addButton}]];
[tableHeader addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[field]-|"
                                                                    options:kNilOptions
                                                                    metrics:nil
                                                                      views:@{@"field": self.palletTagField}]];

UITableView *palletTable=[[UITableView alloc] init];
[palletTable registerClass:[UITableViewCell class] forCellReuseIdentifier:@"palletTagCell"];
[palletTable setEditing:YES];
self.palletTagTable=palletTable;
palletTable.tableHeaderView=tableHeader;
[palletTable setTranslatesAutoresizingMaskIntoConstraints:NO];
[palletTable setDataSource:self];
[palletTable setDelegate:self];

[self.contentView addSubview:palletTable];

[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[pallets]-|"
                                                                         options:kNilOptions
                                                                         metrics:nil
                                                                           views:@{@"pallets":palletTable}]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[last]-[pallets(>=400)]"
                                                                         options:kNilOptions
                                                                         metrics:nil
                                                                           views:@{@"last": lastObject,
                                                                                   @"pallets":palletTable}]];

Sample output from debugger:

[ANONYMIZED][31422:70b] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x8f77810 H:|-(NSSpace(20))-[UITextField:0x8f6ad70]   (Names: '|':UIView:0x8f77650 )>",
    "<NSLayoutConstraint:0x8f77860 H:[UITextField:0x8f6ad70]-(NSSpace(8))-[UIButton:0x8f77500]>",
    "<NSLayoutConstraint:0x8f778d0 H:[UIButton:0x8f77500]-(NSSpace(20))-|   (Names: '|':UIView:0x8f77650 )>",
    "<NSAutoresizingMaskLayoutConstraint:0x8fad160 h=--& v=--& H:[UIView:0x8f77650(0)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x8f77860 H:[UITextField:0x8f6ad70]-(NSSpace(8))-[UIButton:0x8f77500]>

Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
[ANONYMIZED][31422:70b] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x8f77940 V:|-(NSSpace(20))-[UITextField:0x8f6ad70]   (Names: '|':UIView:0x8f77650 )>",
    "<NSLayoutConstraint:0x8f77980 V:[UITextField:0x8f6ad70]-(NSSpace(20))-|   (Names: '|':UIView:0x8f77650 )>",
    "<NSAutoresizingMaskLayoutConstraint:0x8fad1c0 h=--& v=--& V:[UIView:0x8f77650(0)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x8f77980 V:[UITextField:0x8f6ad70]-(NSSpace(20))-|   (Names: '|':UIView:0x8f77650 )>

Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
Community
  • 1
  • 1
RonLugge
  • 5,086
  • 5
  • 33
  • 61

1 Answers1

2

Possible duplicate of this thread: Why am I getting a "Auto Layout still required after executing -layoutSubviews" error every time my app launches now?

Setting 'translatesAutoresizingMaskIntoConstraints' to YES has the affect of converting the auto-resizing constraints of a view into layout constraints that can then be satisfied by the layout engine.

The issue here is that you are specifying that this should not occur, and that instead a bunch of constraints have been created to describe the layout of the view. As a UITableView does not create these constraints, auto layout will 'still be required'.

It might be useful for you to post the initial constraints that are breaking and perhaps some code detailing the setup of your layout constraints.

Community
  • 1
  • 1
mitchellallison
  • 211
  • 1
  • 5