Debugging Autolayout issues in the Xcode

With the release of new iPhone devices in addition to older models iPhone4 and iPhone5, we developers are all forced to switch to autolayout instead of using manual frames to update view layout.

As we extensively use autolayout, goof ups are very much likely. I always miss something or add unnecessary constraint which sometimes crash an app or spit out nasty warnings in the console.

Today, I will tell you my story of how I debugged constraints in the form of this blog post. I will tell you techniques you will need to use to debug potential warnings, as well as how to decode assembly to deal with breaking constraints.

First to demonstrate my point, we will add breaking constraints to the view.


let sampleView = UIView()      
sampleView.translatesAutoresizingMaskIntoConstraints = false
sampleView.backgroundColor = UIColor.redColor()
sampleView.accessibilityIdentifier = "Sample View"
self.view.addSubview(sampleView)
        
self.view.accessibilityIdentifier = "Super View"
let views = ["sampleView": sampleView]
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[sampleView(100)]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[sampleView(100)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
        

As you can see above, I have intentionally added a ambiguous constraint

"H:|[sampleView(100)]|"

In order to better debug, I have also added accessibilityIdentifier for view and corresponding superview. This will help us spot views with breaking constraint easier as follows. When I run this app, I get following debug log letting me know about broken constraints.

breaking_constraints_notification

As it is clear from debug log, Xcode will also tell which constraint it is going to break as a result of ambiguous layout.


Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7ffac9a22f80 H:[Sample View]-(0)-|   (Names: Super View:0x7ffac9a1fde0, Sample View:0x7ffac9a15430, '|':Super View:0x7ffac9a1fde0 )>

Note that since we have added accessbilityIdentifier to views, they are immediately recognizable in the debugger. This is a good trick to apply!

As suggested by debugger, we will add symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints. This will halt the execution when ambiguous constraints are encountered.

ambiguous_constraints_breakpoint

As expected, it will halt the program execution and present with following assembly code,

assembly_code_breaking_constraint_breakpoint

Just like you, I don't get what's going on there. So what I will do, go to debugger and type command po $r15. This will give you the details description of constraint that is broken along with views and their addresses associated with it.

broken_constraints_debugging

If you want more detailed description of all constraints added in addition to breaking constraint, you can type po $r14 in the debugger

Details_of_constraints

Now looking at all this information, you know the list of constraints for view under consideration, breaking constraints and constraints taking precedence. You also have addresses of underlying views should they help in any way.

For e.g. Looking at debug log, we get following addresses for respective views

  • Sample View - 0x7fac08e217c0
  • Super View - 0x7fac08e1eb40

If you want to highlight them for visual inspection, you can even alter their properties on runtime using memory addresses as follows,


(lldb) expr ((UIView *)0x7fac08e217c0).backgroundColor = [UIColor yellowColor]

Where,

  • expr is used to evaluate runtime expression in debugger
  • 0x7fac08e217c0 is the address of view we are trying to debug
  • (UIView *) is used to cast memory address into UIView object
  • Once this address is cast, we can treat it as UIView object and update the property

Please note that sometimes after evaluating UIView subclass appearance from command line like this won't immediately update the UI. iOS usually waits until next run loop or any user event such as tap or swipe occurs on the app. You can force render server to update the display UI with 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 a suspicious address and change the appearance of corresponding view 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.

view_update_runtime

To summarize, in order to avoid breaking constraints scenario you can follow some of the tips below :

  • Look at individual constraint and see if you have added them correctly
  • Watch out for incomplete as well as ambiguous constraint rules
  • Use accessbilityIdentifier to uniquely identify views with breaking constraints in the debugger
  • Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this error in debugger
  • This is generic mistake for iOS newbies - when you create a view and add constraint to it programmatically, make sure to turn the autoresizing mask off by using [view].translatesAutoresizingMaskIntoConstraints = false. (When you do it in the storyboard or xibs, IB will turn this off automatically 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

Reference : This post was inspired by the following blog post, originally published here
http://staxmanade.com/2015/06/debugging-ios-autolayout-issues/

Jayesh Kawli

I am a web and mobile developer working at Wayfair in Boston, MA. I come to learn so many things during course of life and I write about things which helped me and feel like they can help others too.

Subscribe to Fresh Beginning

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!