Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is _UITemporaryLayoutWidth and why does it break my constraints?

I have a storyboard with Autolayout and Size Classes. Pretty complicated layout, and unfortunately I can't really pin down how to reproduce the problem in a new project.
But the view in question is pinned to the left and right edge of the screen with a constraint that has 750 priority (i.e. |-(0@750)-[myView]-(0@750)-|, additionally it has a greater or equal than constraint with a priority of 1000 (i.e. |-(>=0)-[myView]-(>=0)-|). That is done to limit the width on an iPad, so there is a width constraint of width <= 600 @1000, and a center horizontal in container constraint as well. On top of that the view has a aspect ratio constraint of 3:1. As I said, rather complicated.

Interface Builder doesn't show any problems with the constraints. The Xcode layout preview renders correct for all devices.

When I run the app iOS tells me that it has conflicting constraints.

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:0x7fd72853ff80 DMXKit.DipSwitchAssembly:0x7fd72990d0e0.width == 3*DMXKit.DipSwitchAssembly:0x7fd72990d0e0.height>",     "<NSLayoutConstraint:0x7fd728574e50 '_UITemporaryLayoutWidth' H:[DMXKit.DipSwitchAssembly:0x7fd72990d0e0(400)]>",     "<NSLayoutConstraint:0x7fd72856e9c0 V:[DMXKit.DipSwitchAssembly:0x7fd72990d0e0(133)]>" )  Will attempt to recover by breaking constraint  <NSLayoutConstraint:0x7ffb19798000 DMXKit.DipSwitchAssembly:0x7ffb1979a000.width == 3*DMXKit.DipSwitchAssembly:0x7ffb1979a000.height> 

This is repeated a couple of times, with the exact same (i.e. same pointer) constraints. That is strange as well, looks like the constraint isn't really broken. When run, the app looks 100% correct. When I look at the app in the Xcode view debugger, the constraint with the address 0x7ffb19798000 is still there, so it was never broken.

Where does the _UITemporaryLayoutWidth constaint comes from? Obviously I didn't add it. Google doesn't spit out anything useful about _UITemporaryLayoutWidth. Did anyone encounter a problem like this?

like image 405
Matthias Bauch Avatar asked Jun 21 '15 21:06

Matthias Bauch


People also ask

What is constraints in IOS Swift?

Auto Layout constraints allow us to create views that dynamically adjust to different size classes and positions. The constraints will make sure that your views adjust to any size changes without having to manually update frames or positions.

How do you add constraints to a storyboard?

Select the view you would like to constrain. Then tap the button to the right of the one you have selected and use that menu to define your autolayout constraints. If you want it to work for all devices make sure your storyboard is on the wAny hAny size class setting.

What are Xcode constraints?

Most constraints define a relationship between two items in our user interface. These items can represent either views or layout guides. Constraints can also define the relationship between two different attributes of a single item, for example, setting an aspect ratio between an item's height and width.


2 Answers

So, I'm not sure if this helps you with your problem since it sounds like you're building your layout in IB, but here's an issue that I just ran into that may help others that google search for "_UITemporaryLayoutWidth".

My scenario was that I was adding auto layout constraints during init and was accidentally triggering a 'layoutIfNeeded' before adding the view to the view hierarchy (modifying a buttons edge insets triggers layout). It looks like the system adds these temporary constraints and (I assume?) removes them after the view is added to the hierarchy. The temp constraints set 0 dimensions (in my case) which can fail if you, for example, set specific constraint constant values in your layout (e.g., you want 16px between these buttons but there's 0 space in that dimension...)

Update: Investigated a little more and found that the temporary constraint seems to correspond to the frame that you use to initialize the parent view. In my case, the frame I used was size 0x0, so the temp constraint evaluated relative to 0x0 size, thus failing. Verified that if I init with a 5x5 frame then I see the same error with _UITemporaryLayoutWidth(5) constraint. The other thing that I've noticed is that the constraint seems to be added and removed during the layout evaluation - if I break right before I trigger the layout and analyze the constraints then I don't see the temp constraints. I also don't see the constraints after the error, so I suspect they synthesize the temp constraints, add them, solve then remove them.

Update 2: Ok, maybe this is TMI but this might be of some use to someone. My current thought is that these temp constraints are a peek into how the system handles mixed frame manip and autolayout within a single view hierarchy. In my case, my view had no parent and had no constraints defining its size, but it did have a zero frame which meant the system assumed that's the size it should use when solving the layout. My thought is that the system synthesizes these temp constraints for views that have their frames set explicitly to solve the rest of the system as it's traversing the hierarchy.

Update 3: So, I ran into this problem again and wanted to share a little more info. My scenario was that I was trying to essentially measure views that had no parent using the systemLayoutSizeFittingSize: method. Long story short, I had to call layoutIfNeeded on the view before measuring it - this is where I run into the conflict with the temp constraints since the view doesn't have a superview. The temp constraint constants (the dimensions) do correspond to whatever frame is set on the view without a superview - I think this makes sense (though, setting a frame on a view that you're going to be using with AutoLayout seems odd...) I was able to get around the temp constraint issue by saying - if the view doesn't have a superview then add it to a temporary superview; measure; remove it from the temporary superview. Hope this is useful.

like image 116
tyler Avatar answered Oct 12 '22 10:10

tyler


As mentioned above the temporary constraints appear to be set on views that don't have a parent view. I found that ensuring translatesAutoresizingMaskIntoConstraints is false on the top level view removed the temporary constraints. As:

topView.translatesAutoresizingMaskIntoConstraints = false 
like image 33
Nick Ager Avatar answered Oct 12 '22 11:10

Nick Ager