My layout constraints are fine in Interface Builder but an exception occurs at runtime thanks to some part of the framework applying fixed height and width constraints that I really don't want. Why are they there, and how to turn them off?
They're the last two constraints shown in the logged list:
2014-04-26 09:02:58.687 BBCNews[32058:60b] 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:0xbf478a0 UIView:0xbf4a3c0.height == 0.28125*UIView:0xbf4a3c0.width>",
"<NSLayoutConstraint:0xbf47190 UIView:0xbf4a3c0.leading == BNMyNewsCell_landscape:0xbf48b10.leading>",
"<NSLayoutConstraint:0xbf47160 UIView:0xbf4a3c0.trailing == BNMyNewsCell_landscape:0xbf48b10.trailing>",
"<NSLayoutConstraint:0xbf47130 BNMyNewsCell_landscape:0xbf48b10.bottom == UIView:0xbf4a3c0.bottom>",
"<NSLayoutConstraint:0xbf47100 UIView:0xbf4a3c0.top == BNMyNewsCell_landscape:0xbf48b10.top>",
"<NSLayoutConstraint:0xd4c3c40 'UIView-Encapsulated-Layout-Width' H:[BNMyNewsCell_landscape:0xbf48b10(304)]>",
"<NSLayoutConstraint:0xd4c38a0 'UIView-Encapsulated-Layout-Height' V:[BNMyNewsCell_landscape:0xbf48b10(290)]>"
}
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0xbf478a0 UIView:0xbf4a3c0.height == 0.28125*UIView:0xbf4a3c0.width>
We've started seeing tons of layout conflicts in iOS 11 that include references to these constraints and they are in fact added via the
translatesAutoresizingMaskIntoConstraints
flag. It seems that in iOS 11 there's a lot more AutoLayout magic happening when a view is added to the hierarchy rather than just when the view is laid out (as it seemed to work in previous iOS versions).This is the case that we were running into:
The second step (***) will result in a conflict because the system will add zero size constraints to the view at the time the view is added to the hierarchy. We were setting
translatesAutoresizingMaskIntoConstraints
later as a result of using the PureLayout framework which automatically sets this flag correctly when you constrain the view... That said, in iOS 11 you need to remember to turn offtranslatesAutoresizingMaskIntoConstraints
at construction time, before the view is added to the hierarchy.I suspect Apple thought that defaulting this flag to YES would be way more helpful than it is painful. Unfortunately, this has not been the case.
In my case, I was inadvertently setting up my programmatic constraints twice. As soon as I removed the duplicate call, the conflicts went away.
Definitely seeing this on a
UITableView
'stableHeaderView
. I was able to get this to work with a custom header view by explicitly setting the width equal to that of thetableView
after setting thetableHeaderView
, THEN resetting it after a layout pass has completed.Example code for iOS 9, which assumes you have a
UITableView
passed into your method astableView
and an item to configure it asitem
:Couple of notes, mostly for when I look this up again because I have the memory of a goldfish:
viewDidLayoutSubviews
- I was able to use this technique as long as thetableView
has the appropriate width during setup..xib
and then making sure all items were pinned so that as the view changed width, the height would then update.viewForHeaderInSection
, you're probably better off grabbing something offscreen which you can lay out a la this technique. I haven't had much luck with the self-sizing bits.Based on a ton of observation I believe (but cannot know for certain) that the constraints named
UIView-Encapsulated-Layout-Width
andUIView-Encapsulated-Layout-Height
are created byUICollectionView
and friends, and exist to enforce the size returned by thesizeForItemAtIndexPath
delegate method. I guess it's there to ensure that theUICollectionViewCell
set up bycellForItemAtIndexPath
ends up the size that it was told it would be.Which answers my initial question here. A second question is why were the constraints unsatisfiable? The cell's intrinsic height should have been the same as
UIView-Encapsulated-Layout-Height
. Again, I don't know for certain, but I suspect it was a rounding error (i.e. intrinsic height came to 200.1 pixels, theUIView-Encapsulated-Layout-Height
maybe rounded to 200. The fix I came up with was to just lower the priority of the relevant cell constraint to allowUIView-Encapsulated-Layout-Height
to have the last word.