26

I have a custom UITableViewCell which has a thumbnail and bunch of text. The row height is configured to be calculated automatically using

tableView.estimatedRowHeight = 129;
tableView.rowHeight = UITableViewAutomaticDimension

The row height should be calculated as exactly 138 points. Everything looks great on the iPhone 5. However, on iPhone 6 Plus, the auto row height fails INTERMITTENTLY for random rows with the following log.

(
    "<NSLayoutConstraint:0x17009ddd0 V:|-(20)-[scoop.ThumbnailImage:0x124d2a5a0]   (Names: '|':UITableViewCellContentView:0x124e23200 )>",
    "<NSLayoutConstraint:0x17009de70 UITableViewCellContentView:0x124e23200.bottomMargin == scoop.ThumbnailImage:0x124d2a5a0.bottom + 20>",
    "<NSLayoutConstraint:0x17009e780 V:[scoop.ThumbnailImage:0x124d2a5a0(90)]>",
    "<NSLayoutConstraint:0x17009ef00 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x124e23200(138.333)]>"
)

The last line of the log seems to say that for some reason the row height was calculated as 138.333 instead of 138. I have been banging my head for a while now but I am unable to figure out why this is happening. Can some one please help?

Update: This is how my table view cell looks like.

cell

UPDATE I couldn't get the code out of the main repo since its a part of a bigger project. But I have managed to reproduce the issue with a very simple sane project. Please find it here on github.

drcocoa
  • 1,155
  • 1
  • 14
  • 23
  • can you post the code which calculates the height of the cell? – Andriy Gordiychuk Aug 23 '15 at 23:18
  • I am using the tableView.estimatedRowHeight = 129; tableView.rowHeight = UITableViewAutomaticDimension to calculate the row height in viewDidLoad of my controller. – drcocoa Aug 23 '15 at 23:20
  • still, if it is fully dynamic there should be no error. Even if it is not exactly 168. Are you implying that your views inside the cell are set up in such a way that if you add up all of their height it is exactly 168? – Andriy Gordiychuk Aug 23 '15 at 23:22
  • The thumbnail is configured to be 20 points from the top left and bottom edge of my cell. And the thumbnail height itself is 108 points. Adding up all the spaces and the thumbnail height equals 168. Atleast thats what I expect the dynamic row height to be. – drcocoa Aug 23 '15 at 23:25
  • Does it display wrongly? And what about text labels? I assume they are embedded in a UIView. Do you set its height or is it calculated from the height of labels inside? – Andriy Gordiychuk Aug 23 '15 at 23:26
  • Yes everything displays fine both iPhone 5 and 6 plus. And the logs that I posted appear only in iPhone 6 Plus. Despite of the logs, everything appears fine on the screen. But since the constraints break, every time my debugger pauses. – drcocoa Aug 23 '15 at 23:27
  • The text labels are aligned with the top and bottom edge of the thumbnail. They are not in a UIView. I am adding them directly on tableViewCell. – drcocoa Aug 23 '15 at 23:29
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/87724/discussion-between-andriy-gordiychuk-and-suparngp). – Andriy Gordiychuk Aug 23 '15 at 23:29

3 Answers3

34

This warning is telling you there's a conflict in your constraints. Reduce the priority of the height constraint to 999 and it will go away. Tested it in your Github project and worked perfectly.

enter image description here

Yariv Nissim
  • 13,273
  • 1
  • 38
  • 44
  • 6
    That would work but it still means that the constraint is somehow breaking, doesn't it? – drcocoa Aug 31 '15 at 03:11
  • it means that auto layout can't satisfy it but it'll be as close as possible. your math is off somehow but with auto layout you shouldn't even use an explicit height most of the time – Yariv Nissim Aug 31 '15 at 05:14
  • when the explicit height doesn't fit with the auto layout, setting a lower priority tells it to ignore this specific constraint and keep going. that's the purpose of priorities - to avoid conflicts in different scenarios – Yariv Nissim Sep 04 '15 at 00:48
  • 1
    yeah, make its constraint's priority smaller than its row's content view's solved my problem. thanks! – Linc Sep 06 '18 at 09:47
11

0.333 on a 3x scale display (which iPhone 6+ is) is probably connected with the cell separator.

Note that your constraints don't set up the size of the cell, they set up the size of the contentView. But the cell has to add 2 pixels (= 0.666 points) to the cell height for the cell separator. Autolayout tries to keep view positions on integer boundaries so adding 0.666points to the cell height can result in adding 0.333 to your content height.

You can avoid the error by setting your table separators to None. Although setting up one of the priorities to 999 (usually the bottom priority) as the other answer has suggested is a good solution in general.

Community
  • 1
  • 1
Sulthan
  • 128,090
  • 22
  • 218
  • 270
0

The warning is telling you exactly what the problem is, but you may not realize it. The first three constraints are for a 90 pixel-high image that's 20 pixels below the top of its container, and 20 pixels above its container's bottom margin. That's 130, and that's not compatible with the fourth constraint, which wants a total height of 138. However, because the bottom edge constraint is relative to the container's margin, that adds a certain number of pixels more. Either remove the total height constraint (my recommendation), or change the top and bottom edge amounts.

NRitH
  • 13,441
  • 4
  • 41
  • 44
  • The bottom is constrained to the margin which will add extra 8 points. So the total is 138. The problem is with the extra 0.333 that is calculated by the tableView.rowHeight = UITableViewAutomaticDimension. On an iPhone 5 it correctly calculates the height to be 138 points. – drcocoa Aug 24 '15 at 00:25
  • I just downloaded your project, and the first thing that stands out is that there are two layout errors in the storyboard: the Pink Floyd image and label don't have `y` positions. I'm going to put some in. – NRitH Aug 29 '15 at 03:54
  • All the required constraints are present. Just increase the row height by one point. I have updated the project. Please pull the latest code. – drcocoa Aug 29 '15 at 03:56
  • No, they aren't. And why is your cell's contentView 109 pixels high, when the cell itself is 110? Weird. – NRitH Aug 29 '15 at 03:59
  • I must have checked it in like that by mistake. But if you pull the latest code, there won't be any errors on the story board. :) – drcocoa Aug 29 '15 at 04:01
  • And something looks very wrong on the 6+ simulator when I run it. The icons are wider than 90px, they overlap the labels, and the whole table overlaps the status bar. Investigating... – NRitH Aug 29 '15 at 04:02
  • 1
    Alright, I got it! First, I set the icon's bottom constraint to 9, not 10, and that got it closer to the 109 pixel height that the `contentView` wants to have. However, I also had the weird rounding error that you were seeing with the extra 0.333. I fixed it by decreasing the priority of the bottom constraint to 500, so that it won't conflict with the 109 height that the cell is trying to enforce. See also http://stackoverflow.com/questions/23308400/auto-layout-what-creates-constraints-named-uiview-encapsulated-layout-width-h. – NRitH Aug 29 '15 at 04:13
  • PR issued against your GitHub repo. :) – NRitH Aug 29 '15 at 04:20
  • Some suggested that already on the chat. But reducing the priority means the constraint is still breaking under the hood. Its such a simple use case and yet so frustrating. – drcocoa Aug 29 '15 at 04:21
  • I ll merge it as soon as I m back to my computer. – drcocoa Aug 29 '15 at 04:23
  • 1
    I think that it's a bug in how the contentHeight calculates the total height that it wants. – NRitH Aug 29 '15 at 04:23
  • But even if you try to compute the height manually by laying out a dummy cell and returning its height in the heightForRow method, this rounding error appears there as well :/. – drcocoa Aug 29 '15 at 04:24
  • I agree that it's weird. I've never had it happen on anything I've worked on. – NRitH Aug 29 '15 at 04:30
  • 3
    @suparngp In my experience, the constraint conflict warnings mentioning encapsulated-height-constraints are often caused by a _transient_ state of constraint conflict in `UITableView`'s own logic. After `UITableView` first creates a cell, it has its default height installed as a constraint. When it calls `systemLayoutSizeFittingSize:` to size the contentView, that method's execution emits the error, but UITV will size correctly. Because it's a transient issue, lowering the priority does not mean you are accepting an incorrect cell layout. You're just working around a spurious warning. – algal Aug 31 '15 at 07:17
  • @algal this seems like the best explanation. – drcocoa Sep 04 '15 at 04:06