I’ve been working with Swift primarily over the last month. Recently I started working on a new custom interface piece that was having some rendering issues with its layout constraints. I went into LLDB and quickly realized that using private methods such as
recursiveDescription to print out a hierarchy of my views and see ambiguity wasn’t possible out of the box.
The reason for this is that when you’re in a Swift frame, LLDB is expecting you to call a Swift method it knows about. Since
_autolayoutTrace and the like are private API, they don’t have any visibility to Swift. Safety!
There are a few different ways to get around this. The first is straight in LLDB. You can use the expr command to tell LLDB that you are passing it a snippet of Objective-C code like so:
expr -l objc++ -o -- [[UIWindow keyWindow] _autolayoutTrace]
What we’re doing here is printing out our entire view hierarchy to the debugger. Frequently typing that long of a statement is obviously a bit tedious, so I tend to put it in my .lldbinit file.
command alias alt expr -l objc++ -O --[[UIWindow keyWindow] _autolayoutTrace]
Now you can just type alt and get the same output from the debugger.
You’ll notice that I am throwing this out for the entire contents of the keyWindow. I haven’t been able to find a way to pinpoint it down a single property such as self.view, so if you have any feedback on that, please share!
If you’re mixing Objective-C and Swift, you likely already have a bridging header. You can bridge add a category on UIView that exposes the recursiveDescription and _autolayoutTrace methods to Swift.
#ifdef DEBUG @interface UIView (LayoutDebugging) #pragma clang push #pragma clang diagnostic ignored “-Wincomplete-implementation” - (id)recursiveDescription; - (id)_autolayoutTrace; #pragma clang pop @end #endif And the implementation file. #import “UIView+LayoutDebugging.h” #ifdef DEBUG @implementation UIView (LayoutDebugging) // Nothing to see here! @end #endif
Let’s walk through this. You’ll notice that I have the entire thing wrapped in an #ifdef DEBUG statement because I am working with private APIs that I presume the App Store usage checker would flag and reject your app against. With the #ifdef, I am saying that it should only be included on development builds. Apple will have no idea what abuses we are committing since it will never make it to the release builds!
The other atrocity I am committing in this file is the use of #pragma clang diagnostic to tell the compiler to ignore any ‘uninmplemented method’ warnings that will pop-up from not being able to find an implementation for the two methods we defined in our category. Since they exist as private API, we don’t need to reimplement them.
Now if you break in a Swift frame with LLDB and try to call self.view._autolayoutTrace() you’ll get an output you expected.
If you’ve found this post useful, and want to learn more about how to best take advantage of Auto Layout in your OS X and iOS apps, be sure to purchase my new book Achieving Zen With Auto Layout