Tom Kraina Tom Kraina - 6 months ago 23
Swift Question

How to use _printHierarchy in LLDB console with Swift?

Apple added a private helper

in iOS8 that can be used in LLDB console:

po [[[UIWindow keyWindow] rootViewController] _printHierarchy]


which prints out the whole view controller hierarchy in text form.

This works only if you are debugging code on Objective C. In Swift, however, this doesn't work:

(lldb) po [[[UIWindow keyWindow] rootViewController] _printHierarchy]
error: <EXPR>:1:13: error: expected ',' separator
[[[UIWindow keyWindow] rootViewController] _printHierarchy]
^
,
<EXPR>:1:24: error: expected ',' separator
[[[UIWindow keyWindow] rootViewController] _printHierarchy]
^
,
<EXPR>:1:44: error: expected ',' separator
[[[UIWindow keyWindow] rootViewController] _printHierarchy]
^
,


An equivalent usage in Swift doesn't work either:

po UIApplication.sharedApplication().keyWindow!.rootViewController!._printHierarchy


ends up with an error (probably because
_printHierarchy
is a private property):

(lldb) po UIApplication.sharedApplication().keyWindow!.rootViewController!._printHierarchy()
error: <EXPR>:1:64: error: 'UIViewController' does not have a member named '_printHierarchy'
UIApplication.sharedApplication().keyWindow!.rootViewController!._printHierarchy
^ ~~~~~~~~~~~~~~~


The question is: How to print out the view controller hierarchy in Swift? Or is there a way how to use ObjC in LLDB console even in Swift projects?

Rob Rob
Answer

You point out how one shows the view controller hierarchy with:

po [[[UIWindow keyWindow] rootViewController] _printHierarchy]

You then say:

This works only if you are debugging code on Objective C. In Swift, however, this doesn't work.

Actually, this depends a little upon how you pause the execution of your Swift program. The issue is that the expression command (which po uses) will use Swift expressions in Swift frames, and Objective-C expressions in Objective-C frames. Thus this means that the po behavior varies depending upon how the execution pauses:

  • You can, for example, press the "pause" button while the app is running:

    pause

    If you do this, you will be able to use the above po syntax with the Objective-C expression without incident.

  • If, on the other hand, you set a breakpoint inside your Swift code, you'll be in a Swift frame when you get to the (lldb) prompt. But you can explicitly tell the expression command that you want to use the Objective-C syntax with the -l (or --language) option:

    expr -l objc++ -O -- [[[UIWindow keyWindow] rootViewController] _printHierarchy]
    

This ability to specify the language in the expr command is discussed in WWDC 2014 video Advanced Swift Debugging in LLDB.