15

I'm using auto layout constraints programmatically and I am constantly seeing the same kind of error across my application usually related to a constraint that looks like this:

"<NSAutoresizingMaskLayoutConstraint:0x82da910 h=--& v=--& V:[UITableViewCellContentView:0x82d9fb0(99)]>"

I've put some sample code to reproduce at https://github.com/nicolasccit/AutoLayoutCellWarning

In this example, I am creating a very simple view with 2 UI elements: an image view called imageThumbnail and a label called labelName with some constraints:

"H:|-padding-[_imageThumbnail(==imageWidth)]-[_labelName]";
"V:|-padding-[_imageThumbnail(==imageHeight)]-padding-|";
"V:|-padding-[_labelName]";

On both elements I set the AutoresizingMaskIntoConstraints to NO.

And I am getting the following exception:

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:0xa6e4f90 V:[UIImageView:0xa6e4340]-(10)-|   (Names: '|':UITableViewCellContentView:0xa6e4150 )>",
    "<NSLayoutConstraint:0xa6e4f10 V:[UIImageView:0xa6e4340(80)]>",
    "<NSLayoutConstraint:0xa6e4ed0 V:|-(10)-[UIImageView:0xa6e4340]   (Names: '|':UITableViewCellContentView:0xa6e4150 )>",
    "<NSAutoresizingMaskLayoutConstraint:0xa6e4ac0 h=--& v=--& V:[UITableViewCellContentView:0xa6e4150(99)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0xa6e4f90 V:[UIImageView:0xa6e4340]-(10)-|   (Names: '|':UITableViewCellContentView:0xa6e4150 )>

I know the last constraint is related to the content view but I am unclear to properly remove it (Setting
AutoresizingMaskIntoConstraints to NO on the contentView raises an error and in the SO link below, it messes up the entire layout):

<NSAutoresizingMaskLayoutConstraint:0xa6e4ac0 h=--& v=--& V:[UITableViewCellContentView:0xa6e4150(99)]>

I've seen the answers at: Auto layout constraints issue on iOS7 in UITableViewCell but none of them seem to be working for me here.

I believe that the constraints I define are valid and pretty straightforward but can't seem to figure out what's going on. And I'm seeing the exception being raised both in iOS 6.1 and iOS 7.

Any idea what I am doing wrong here?

Thanks, Nicolas

Community
  • 1
  • 1
nicolasccit
  • 161
  • 1
  • 1
  • 6

2 Answers2

8

You should read the exception description more thoroughly:

Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints

In short, this constraint you are seeing is due to some UIView having it's translatesAutoresizingMaskIntoConstraints set to YES. In this case I would suspect this is the content view of the cell, as hinted to by UITableViewCellContentView.

You can disable it by just setting the property to NO.

cell.contentView.translatesAutoresizingMaskIntoConstraints = NO

EDIT: Now, keep in mind that this is a temporary fix, most likely you have some other logic error with your constraints, for example constraining something in the contentView of the cell to the cell itself. Or by seemingly forcing the contentView to be larger than the cell is (and therefore larger than its' automatic sizing is).

For example, is your cell tall enough? i.e is it tall enough so that the contentView is 100pt tall? Note that the contentView has to be that tall, which might not necessarily match the height of the cell.

Henri Normak
  • 4,695
  • 2
  • 23
  • 33
  • Thanks for the answer but I don't believe this is correct. I don't believe you're supposed to set the autoResizingMaskIntoConstraints on the contentView. First, in the SO question I link to, it is explained: "I cannot set the translatesAutoresizingMaskIntoConstraints property of the contentView to NO => it would mess up the entire cell." and in my case, if I try, I get the following exception: "Terminating app due to uncaught exception 'NSInternalInconsistencyException". Unless there is something else I am missing. – nicolasccit Jan 13 '14 at 19:05
  • This might help with the latter exception. http://stackoverflow.com/questions/12610783/auto-layout-still-required-after-executing-layoutsubviews-with-uitableviewcel But yes, ideally you would not need to manipulate said property, in your case you obviously have a logic error in your layout sizes... For example, get rid of the height constraint on the image and log out it's frame after the layout has completed, I suspect it will not be 80pt (meaning there is simply not enough room to achieve the layout you want). – Henri Normak Jan 13 '14 at 19:09
  • If I remove the height constraint on the image, the exception disappears and the frame height becomes 23.0. Although the UI is identical as when I have the constraint. When I let the constraint and print the frame height for the image, it is 80.0. – nicolasccit Jan 13 '14 at 19:30
  • Thanks for the edit. What do you mean by "is your cell tall enough?". I don't hardcode the height of a cell. The example I put on github is a dumb one where all cells happen to have the same height but I use the heightForRowAtIndexPath to compute the height for each cell. Am I missing something? – nicolasccit Jan 13 '14 at 19:32
  • @HenriNormak Thanks alot – Monika Patel Sep 27 '16 at 06:17
5

I've put a corrected version of your code at https://github.com/mattneub/AutoLayoutCellWarning. Works perfectly. This line was the main cause of your trouble:

NSString *const kImageVertical = @"V:|-padding-[_imageThumbnail(==imageHeight)]-padding-|";

Change that to

NSString *const kImageVertical = @"V:|-padding-[_imageThumbnail]-padding-|";

And all will be well.

The main reason you were having trouble is that by assigning an absolute height to the image view, you were making it impossible to also assign a height to the cell. Floating point is not exact, so you need to allow some room for the cell to grow / shrink. If we take away the absolute height, the image view gets its height from its intrinsic content size, at a lower priority, so there is no conflict.

I have some other critiques of your code. In trying to do dynamic setting of the cell's height while using auto layout, you were giving layout and constraint update commands you should never be giving, and you are giving them at wrong times. It is possible to do dynamic row heights based on constraints, but the way you're doing it is not the way. All you have to do is call systemLayoutSizeFittingSize to find out the correct cell height. Also, there is absolutely no need to put your "hidden" cell into the interface. Don't do that; it just confuses things. One of the things you'll notice when you look at my version of the code is that it is much simpler than yours, because of those differences.

For a working method, see my example at https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch08p424variableHeights/ch21p722variableHeights/RootViewController.m

And see the discussion of this issue in my book.

EDIT (May 2014): Unfortunately my answer above fails to point out one of the key causes of this problem, namely, that the cell separator has height (if it hasn't been set to None). Therefore if you assign the cell a height that doesn't take the separator height into account, the auto layout constraints, if absolute, cannot be resolved into that height. (See this answer, which really made the lightbulb come on inside my head.)

Community
  • 1
  • 1
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Interesting. If I try this, I am getting the following exception: "*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. TableViewCell's implementation of -layoutSubviews needs to call super.'" Did you add it just after the line: "if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {"? – nicolasccit Jan 13 '14 at 19:24
  • Hi Matt, I've been trying to follow this to setup my constraints and layout commands: http://stackoverflow.com/questions/18746929/using-auto-layout-in-uitableview-for-dynamic-cell-layouts-variable-row-heights For the simple case, I have on github, I don't really need flexible cell height, but I do in my real case with multi line labels. Would you mind clarifying what I am doing wrong? Basically, why I should "never be giving" those commands or "giving them at wrong times"? – nicolasccit Jan 13 '14 at 19:39
  • I've tried removing the padding on the constraint and it removes the warning and as you said the row height now is the issue. I could set the height manually in this example, but in my real use, different cells will have different heights. Conceptually, in this very simple example, I am trying to say: - the image should be 10pt from the top and 10pt from the bottom and 80pt high. - and the height of the cell should be computed automatically in the viewController. For this, I just create a hidden cell whose purpose is to do just that. – nicolasccit Jan 13 '14 at 19:52
  • Because layout is going to happen anyway, all by itself. Don't interfere by re-forcing it. The cell is going to be resized to the row height and the table width; don't monkey with that process. – matt Jan 13 '14 at 19:52
  • Calm down, I'm not finished. – matt Jan 13 '14 at 19:53
  • I am pretty calm :) Thanks a lot for the help :) In this example, you can remove the two lines: [cell setNeedsLayout]; [cell layoutIfNeeded]; from the heightForRowAtIndexPath method. And the problem would still remain. In some other use case I have, I am working with multi-line labels and according to this: http://stackoverflow.com/questions/18746929/using-auto-layout-in-uitableview-for-dynamic-cell-layouts-variable-row-heights, you have to re-force layouting to get the proper label height. – nicolasccit Jan 13 '14 at 19:57
  • @nicolasccit Okay, sorry, I had to go out for a while... I've put a corrected version of your project on my github site, at https://github.com/mattneub/AutoLayoutCellWarning. Works perfectly. I've added some discussion of it to my answer above. – matt Jan 14 '14 at 02:33
  • I came up to the same conclusion regarding the height constraint. This still seems strange to me as I am specifying the exact height I expect for the image. Regarding the cell height code, in this use case, you are correct that all the code I'm calling is useless. I'll get back to my more realistic example with a multi-line UILabel and see if I can remove that code there as well but I believe I would have to call the layout method myself as this requires multiple pass to correctly set the height. Thanks a lot for the help! – nicolasccit Jan 14 '14 at 15:57
  • You're welcome for the help and you are very welcome to Stack Overflow! – matt Jan 14 '14 at 16:01
  • Critical quote that fixed my similar problem: "by assigning an *absolute height* to the image view, you were making it impossible to also assign a height to the cell [...] If we take away the absolute height, the image view gets its height from its intrinsic content size, *at a lower priority*, so there is no conflict."—I had to change one of my heights to a low priority so Auto Layout could break it, then everything worked. – Robert Atkins May 21 '14 at 07:16
  • 1
    @RobertAtkins Unfortunately my answer fails to point out one of the key causes of this problem, namely, that the _cell separator has height_. Therefore if you assign the cell a height that doesn't take the separate height into account, the auto layout constraints, if absolute, cannot be resolved into that height. I've added an edit to that effect. – matt May 21 '14 at 15:39
  • 1
    @matt, the link to your example project on Github 404s. – Robert Atkins Jun 02 '14 at 10:00
  • @RobertAtkins Having explained the problem I took down the fork. – matt Jun 02 '14 at 16:48