Constraints not installed for a size class still generate autolayout conflicts at runtime when this size class is in use

Originator:defagos
Number:rdar://27679115 Date Originated:03-Aug-2016 05:43 PM
Status:Open Resolved:
Product:iOS SDK Product Version:9 and 10
Classification:Serious bug Reproducible:Always
 
Summary:
The use of autolayout and size classes makes it possible to create very different layouts for a view, within a single storyboard or xib file.

For example, it is possible to create a layout where a label is displayed horizontally centered below an image for almost all size classes, except for some size class (say the compact height) for which the label should be displayed vertically centered to the right of the image. 

To be able to create such layouts, constraints can be selectively installed or uninstalled independently for each size class, right within Interface Builder (open the Xcode Size Inspector, select the constraint and check and uncheck 'Installed', creating a special rule for any size class requiring it)

To implement the example layout described above:

- The two constraints horizontally centering the label below the image would be installed for all size classes, except for the compact height size class for which they would not be installed
- The two constraints vertically centering the label on the right of the image would be only installed for the compact height size class

Such setups work in most cases well, but I discovered that they might generate autolayout conflicts in the case of collection view cells. If a cell is namely displayed when the app uses the size class specialisation for which exceptions were made (in our example above the compact height one), layout constraints which have not being marked as installed for this size class still show up in conflicts with other installed constraints.

Steps to Reproduce:
I created a small sample project (see Attachments) implementing several layouts where an image and a title are positioned differently depending on the size class, as described above. These layouts are made as follows:

a) Simple view controller view
b) Table view with prototype cells
c) Collection view with prototype cells
d) Table view with cells instantiated from a xib file
e) Collection view with cells instantiated from a xib file

For debugging purposes, the project logs the 4 constraints which are not always installed depending on the size class.

You should play with this project as follows:

1. Run the project with an iPhone Plus device or simulator (i.e. supporting landscape compact orientation on the springboard), rotated in landscape orientation

2. The project starts with the simple view example selected. Rotate the device into portrait orientation, then back into landscape orientation. In the Xcode console, you can see that constraints are correctly installed depending on the involved size class. No autolayout conflicts are reported to the console

3. Switch to the Table (prototype) tab and rotate the device twice again. Everything works as expected. The behavior is therefore correct for prototype table view cells

4. Switch to the Table (xib) prototype and rotate the device twice again. Everything works as expected. The behavior is therefore correct for table view cells instantiated from a xib

5. Your device should now be held in landscape orientation. Open the Collection (prototype) tab and check the console. You will see that autolayout conflicts are logged. The involved constraints are 'debug_label_image_vertical_distance' (constraint positioning the label below the image for all size classes, not installed for compact height) and 'debug_vertical_label_centering' (constraint positioning the label centered next to the image, installed for the compact height size class only). Those constraints should not appear for the same compact size together, yet they are in conflict, leading to a broken layout
6. You can repeat this test with the Collection (xib) example. The issue is therefore the same, whether the cell is a prototype one or is instantiated from a xib

Note that there are no issues if all these examples are opened in portrait orientation first.

Expected Results:
Constraints not installed for a size class never conflict with other installed constraints when this size class is in use.

Actual Results:
Constraints not installed for a size class can create autolayout conflict with other installed constraints when this size class is in use.

Version:
Tested on iOS 9, as well as on iOS 10 beta 4

Notes:


Configuration:
Any device

Code sample available at: https://github.com/defagos/radars/tree/develop/uninstalled-constraint-bug

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!