With the release of new iPhone devices in addition to older models iPhone4 and iPhone5, developers are forced to switch to autolayout instead of using manual frames to update our view layouts.
As we extensively use autolayout, goof-ups are very much likely to happen. I always miss something or add unnecessary constraints which sometimes crashes an app or spit out unwanted warnings in the console.
Today, I will tell you my story of how I debugged breaking constraints in the form of this blog post. I will tell you techniques you will need to use to debug warnings, as well as how to decode cryptic console error messages to fix the breaking constraints.
First, to demonstrate my point, we will add breaking constraints to the view.
let sampleView = UIView() sampleView.translatesAutoresizingMaskIntoConstraints = false sampleView.backgroundColor = UIColor.yellow sampleView.accessibilityIdentifier = "Sample View" self.view.addSubview(sampleView) self.view.accessibilityIdentifier = "Super View" let views = ["sampleView": sampleView] self.view.addConstraints( NSLayoutConstraint.constraints(withVisualFormat: "H:|[sampleView(100)]|", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: views) ) self.view.addConstraints( NSLayoutConstraint.constraints(withVisualFormat: "V:|[sampleView(100)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: views) )
As you can see above, I have intentionally added an ambiguous constraint
In order to better debug, I have also added
accessibilityIdentifier to view and corresponding superview. This will help us to easily spot views with breaking constraints. When I run this app, I get the following debug log letting me know about broken constraints.
As it is clear from debug log, Xcode will also tell which constraint it is going to break as a result of an ambiguous layout.
Will attempt to recover by breaking constraint <NSLayoutConstraint:0x600002afc910 H:[Sample View]-(0)-| (active, names: Super View:0x7fba4e5060b0, Sample View:0x7fba54204bf0, '|':Super View:0x7fba4e5060b0 )>
Note that since we have added
accessbilityIdentifierto views, they are immediately recognizable in the debugger. This is a good trick to apply for getting easier readability
As suggested by the debugger, we will add a symbolic breakpoint at
UIViewAlertForUnsatisfiableConstraints. This will halt the execution when ambiguous constraints are encountered.
- Go to Breakpoint navigator
- Click on
+icon at the bottom-left corner
- Choose an option
UIViewAlertForUnsatisfiableConstraintsunder symbol option
- Press enter
- Restart the app
As expected, it will halt the program execution and present with the following assembly code,
Initially, when I looked at this code, I didn't quite get what was going on here. But let's start debugging this assembly code by printing the information we need in order to debug autolayout issue.
You can go to debug console and type
po $rbx. It will print description of views with breaking constraints as follows,
(lldb) po $rbx <UIView: 0x7fe797f1aba0; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x60000109c2a0>>
This message can be used to inspect the size dimension of faulting view as well as its memory address for follow-up debugging steps
Now going back, let's take a look at debug log, we get the following addresses for respective views
Sample View: 0x7fba00e07c20- View with breaking constraints
Super View: 0x7fba00e081d0- A parent view associated with a view having breaking constraints
There are two ways to inspect this view.
1. Through view debugger
This is the easiest way to capture the view with breaking constraints. When Xcode detects the view with breaking constraints, it will print a message which looks something like this,
Will attempt to recover by breaking constraint <NSLayoutConstraint:0x600000f7d590 H:[Sample View]-(0)-| (active, names: Super View:0x7fba00e081d0, Sample View:0x7fba00e07c20, '|':Super View:0x7fba00e081d0 )>
Looking at this log, you will know that the view
Sample View is undergoing breaking constraints and the address associated with it is
The next step we will do is to capture the view hierarchy and try to locate this view in this hierarchy,
- Go to Debug menu in Xcode
Capture View Hierarchy
It will display details view hierarchy as follows,
While Xcode is displaying this view hierarchy in the left menu bar, filter this hierarchy by entering the view address in the bottom filter menu and it will immediately highlight the view with breaking constraints.
Once you locate this view, you can take the next steps to analyze why constraints are breaking and what you can do to fix them.
2. Through Debug console
If you want to directly highlight views with breaking constraints for visual inspection, you can even alter their properties on runtime using memory addresses as follows,
- Go to Debug menu
The program will pause and then you can go to debug console and execute the following command,
(lldb) expr ((UIView *)0x7fba00e07c20).backgroundColor = [UIColor purpleColor]
expris used to evaluate runtime expression in the debugger
0x7fba00e07c20is the address of view we are trying to debug - in our case view with breaking constraints
(UIView *)is used to cast memory address into
- Once this address is cast, we can treat it as
UIViewobject and update the property
Please note that sometimes after evaluating
UIView subclass appearance from a command line like this won't immediately update the UI. iOS usually waits until the next run loop or any user event such as tap or swipe occurs on the app. You can force the render server to update the display UI with the following command.
e (void)[CATransaction flush]
Using this trick, even if you are not able to locate faulted view in the debugger, you can grab an address of a suspicious view and change its appearance to provide a visual cue on screen
As you can see I have changed the background color of view for which constraints were breaking and now it appears like this.
To summarize, in order to avoid breaking constraints scenario you can follow some of the tips below :
- Look at individual constraints and see if you have added them correctly
- Watch out for incomplete as well as ambiguous constraint rules
accessbilityIdentifierto uniquely identify views with breaking constraints in the debugger - this will help you easily locate view with breaking constraint just looking at the debug log
- Make a symbolic breakpoint at
UIViewAlertForUnsatisfiableConstraintsto break and catch this error in the debugger
- This is a generic mistake for iOS newbies - when you create a view and add a constraint to it programmatically, make sure to turn the autoresizing mask off by using
[your_view].translatesAutoresizingMaskIntoConstraints = false. (When you do it in the storyboard or xibs, Interface builder will automatically turn it off for you.)
These are some of the steps I find useful while debugging autolayout issues. If you know any problems with them or have your own tips dealing with fixing autolayout issues, I would love to hear them