Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Debugging programmatic autolayout constraints

I've created my view controller's view entirely in code by adding subviews and constraints (using the CocoaPod PureLayout). It actually looks/ functions exactly how I want it to, but xcode yells at me saying one of the constraints is wrong and it removes it. How can I tell which UIViews the bad constraints are attached to? I have a lot of subviews and I can't figure it out from context. When working with constraints in interface builder, you can name the UIView and that's what gets printed to the debug console- but I can't find a way to accomplish this through code.

Looking at the apple docs: https://developer.apple.com/library/ios/documentation/userexperience/conceptual/AutolayoutPG/ResolvingIssues/ResolvingIssues.html#//apple_ref/doc/uid/TP40010853-CH17-SW14

They say: "It may be obvious which view has the problem; if it is not, you may find it helpful to use the NSView method _subtreeDescription to create a textual description of the view hierarchy.

Important: The _subtreeDescription method is not public API; it is, however, permissible to use for debugging purposes"

Is this what I'm looking for? How do I make use of a private API?

like image 752
dMurdZ Avatar asked Dec 12 '22 03:12

dMurdZ


2 Answers

Starting with the iOS 8 SDK, there is now an identifier property on NSLayoutConstraint. Note that this property has existed privately (Apple-only) since iOS 7, but now that it is public in iOS 8, you are allowed to make use of it even when running on iOS 7.

Using this property, you can easily set a unique short description to your constraints to aid in debugging. For example, using PureLayout:

NSLayoutConstraint *constraint = [label autoPinEdge:ALEdgeLeft toEdge:ALEdgeRight ofView:imageView];
constraint.identifier = @"Label Left Padding";

// ...or using PureLayout v2.0+:
[[label autoPinEdge:ALEdgeLeft toEdge:ALEdgeRight ofView:imageView] autoIdentify:@"Label Left Padding"];

// PureLayout v2.0+ also supports a block-based version to set an identifier to many constraints at once:
[UIView autoSetIdentifer:@"Constraints to position image view" forConstraints:^{
    // ...a bunch of PureLayout API calls here that create constraints...
}];

Then, you will see this identifier printed next to the constraint in the console if there is a constraint exception.

One other handy debug tool:

Apple has a very handy category on UIView (declared in UIView.h) named UIConstraintBasedLayoutDebugging that includes a method:

- (NSArray *)constraintsAffectingLayoutForAxis:(UILayoutConstraintAxis)axis;

You can call this method on any view, passing either Horizontal or Vertical axis (since constraints in each axis are independent), and get a list of all the constraints that affect the position and size along that axis. Note that Apple says this should be used for debugging only - never ship code that uses this API!

like image 176
smileyborg Avatar answered Jan 12 '23 11:01

smileyborg


UIWindow also has a private instance method _autolayoutTrace to dump a string that shows the overall view hierarchy, including views that are ambiguous. Just use it from the console after setting a breakpoint after you see the constraint exception. You can also trap any autolayout exceptions using a symbolic breakpoint "UIViewAlertForUnsatisfiableConstraints".

Check out Facebook's Chisel too: https://github.com/facebook/chisel

like image 42
Ari Braginsky Avatar answered Jan 12 '23 13:01

Ari Braginsky