Search code examples
xcodeautolayoutinterface-builderxcode-storyboardbuild-error

Interface Builder & Storyboard: treat Autolayout errors as build errors


Is there a way to propagate Interface Builder Conflicting Constraints errors to the rest of the build process and treat them as build errors?

Of course, the LLVM setting Treat Warnings as Errors has no effect on Storyboard errors.

I have this view which clearly can't satisfy all constraints:

can't satisfy all constraints


In Interface Builder:
These errors look like this:

Conflicting Constraints
Can't satisfy all constraints.

enter image description here


In the Xcode Project:
The errors are downgraded to warnings, so that the application compiles, builds, link and run.

enter image description here

How can I prevent the application to build if I have AutoLayout errors in a Storyboard in Interface Builder?


Solution

  • Here's, if not a complete solution, a few avenues to investigate.

    First, note there are two main source of Auto Layout errors/warnings — unsatisfiable constraints and ambiguous constraints — and they get handled in different ways.

    Also note that the full capability of Auto Layout can be exercised only at runtime — Xcode's tools offer some insight into what's going on with the constraints in a storyboard, but that's a bit different from what happens when those constraints are evaluated in a "real" view/window running in an app. ("Real" in quotes because the iOS simulator is just fine for layout debugging... it doesn't have to be a real device.)

    Killing the Build with ibtool

    When Xcode "compiles" your storyboard as part of building your project, it delegates that function to the command line program ibtool. While there doesn't seem to be a way to change how Xcode interprets ibtool output (that is, to treat errors output by ibtool as a reason to stop a build), you can invoke ibtool an extra time yourself.

    1. Add a custom build phase or build rule
    2. In the shell script for that phase/rule, invoke ibtool to process your storyboard(s). Pass --warning or --error to get warning or error output. (Take a look at the build log for a normal build, and/or man ibtool to see what other flags you might want.)
    3. If you detect output indicative of a problem (i.e. non-empty output, if you set yourself up to only receive errors), exit your shell script with a non-zero status code, and Xcode will halt the build.

    Automating Constraint Debugging Post-Build

    As noted, the real test of constraints is in a real layout situation, when your app runs. So a better time to catch constraint problems might not be as part of build automation, but in testing automation.

    • For ambiguous layout, you can detect things easily at runtime with the hasAmbiguousLayout property on UIView. And if you have a Boolean property you can query at runtime, you have the seed of something to put into automated testing. Just write some unit tests that run through your app's UI, test hasAmbiguousLayout for important views, and fail whenever that property is true. Then your continuous integration system can tell you whenever somebody makes a commit that still builds, but breaks the post-commit unit tests.

    • For unsatisfiable layouts, it might be a little bit trickier. The Auto Layout system automatically logs to the console when it detects such problems, so you might be able to write a script for your CI system that looks for "Unable to simultaneously satisfy constraints" in the run logs from your unit testing. Alternately... I'm not sure if it's possible to run with specific Xcode debugger breakpoints active when executing tests through CI, but if it is, you can set a symbolic breakpoint on UIViewAlertForUnsatisfiableConstraints.