NSSplitViewController Auto Layout Bug and Workaround

31st March, 2015 — Aral Balkan

Screenshot of the example project.
Setting one of the two split view items in an NSSplitViewController as collapsed in Interface Builder can cause a runtime constraints error.

You can’t constrain this!

NSSplitViewController has an edge-case Auto Layout bug that manifests when a split view item is set as collapsed in Interface Builder (IB) and then shown at some point after viewDidLoad (e.g., in response to a user action).

It actually took me two days to track down this little rascal so I took the time to create a simple isolated example that replicates the issue.

Download the source here. (Test.zip, 68KB)

The exception thrown by the sample is below:

Error console output:2015-03-31 13:46:32.669 Test[7890:1234827] Unable to simultaneously satisfy constraints:
(
    "<NSLayoutConstraint:0x6080000850a0 H:[_NSSplitViewItemViewWrapper:0x6000001411e0(50)]>",
    "<NSLayoutConstraint:0x6000000879e0 H:|-(0)-[NSView:0x6000001221c0]   (Names: '|':_NSSplitViewItemViewWrapper:0x6000001411e0 )>",
    "<NSLayoutConstraint:0x600000087a30 H:[NSView:0x6000001221c0]-(0)-|   (Names: '|':_NSSplitViewItemViewWrapper:0x6000001411e0 )>",
    "<NSLayoutConstraint:0x600000087620 H:[NSBox:0x10052d0a0'Box'(560)]>",
    "<NSLayoutConstraint:0x600000087760 H:|-(20)-[NSBox:0x10052d0a0'Box']   (Names: '|':NSView:0x6000001221c0 )>",
    "<NSLayoutConstraint:0x6000000877b0 H:[NSBox:0x10052d0a0'Box']-(20)-|   (Names: '|':NSView:0x6000001221c0 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x600000087620 H:[NSBox:0x10052d0a0'Box'(560)]>

Set the NSUserDefault NSConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints to YES to have -[NSWindow visualizeConstraints:] automatically called when this happens.  And/or, break on objc_exception_throw to catch this in the debugger.

As far as I can tell, the problem appears to be this: When Cocoa sees a collapsed split view item, it automatically creates a width constraint with required priority on the also-automatically-created _NSSplitViewItemViewWrapper. Then, if your split view item’s view also has a required width constraint of some sort, they conflict when you set collapsed = false later on.

Workaround

The isolated example I’ve provided should hopefully make it easy for Apple to fix this but, in the meanwhile, there is an easy workaround: Either,

I hope this helps you work around the problem and makes it easier for the folks at Apple to fix it. (rdar://20432741)