4

When I set up an Auto Layout constraint customized by Size Classes, such that the constraint is installed in some Size Class(es), and not in others, I get this Unsatisfiable Constraints error message during runtime but the result is as expected on Interface Builder with no errors / warnings.

enter image description here

enter image description here

What I am testing

For this simplified example, to demonstrate how Unsatisfiable Constraints unexpectedly happen, I want the star image to have fixed height, but custom width based on Size Class. As you can see in the image, I want it fairly big for Regular Width.

Because the width constraint is not installed for Compact Width, it gets the image size based on the intrinsic content of the star image. (Credit: This star is from Use Your Loaf)

The problem

As I rotate the device from landscape to portrait in the simulator running iPhone 8 Plus (iOS 11.1 with Xcode 9.1), I get the following error:

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.

....


Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x6040002839d0 UIImageView:0x7fe177d0b940.width == 480   (active)>

So apparently, this width constraint is still present even when my view is changing to Compact Width, where I specified to have the constraint NOT installed. Why is this? Is using installed the proper way to customize Auto Layout constraints based on different Size Class? I don't see any other way to achieve it in Storyboard though.

I tried creating the width constraint programmatically and setting .isActive from inside traitCollectionDidChange instead, and I still got the same error.

I didn't get such error when testing the sample code from Mysteries of Auto Layout WWDC talk, which is deactivating / activating constraints through traitCollectionDidChange just like I did.

Update

I added my own code on GitHub.

HuaTham
  • 7,486
  • 5
  • 31
  • 50

2 Answers2

4

You can silence this error by lowering the priority of the width constraint to 999.

I believe this warning has something to do with UIView-Encapsulated-Layout-Width constraint which is added automatically by the autolayout engine. There is a lot of questions regarding this type of constraint but I haven't found any good answer what it is and what is it's role. The best I found is this thread.

<NSLayoutConstraint:0x60400008d110 'UIView-Encapsulated-Layout-Width' UIView:0x7ff1e5f08d20.width == 414   (active)>

If you will take a look at the preview of your layout in the view hierarchy debugger you will see that all the constraints are set up as expected in both orientations.

portrait configuration preview Landscape configuration preview

Kamil Szostakowski
  • 2,153
  • 13
  • 19
  • 1
    Thank you for the answer. I did notice this constraint at first too, and I think simply silencing the error this way may simply hide an actual problem, which I'm not quite sure what it is yet. So I'd prefer an answer that actually explains what is going on. – HuaTham Nov 08 '17 at 17:48
1

I had a similar problem where I tried switching between two constraints that were conflicting. My problem was that I was activating the conflicting constraint while the other was active as well and I would get this warning.

Try deactivating the conflicting active constraint first and then activating the new constraint. That will get rid of the warning.

if isWide {
    wideConstraint.isActive = false
    narrowConstraint.isActive = true
else {
    narrowConstraint.isActive = false
    wideConstraint.isActive = true
}
A. Maly
  • 305
  • 5
  • 8