Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use _printHierarchy in LLDB console with Swift?

Apple added a private helper _printHierarchy 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?

like image 877
Tom Kraina Avatar asked Jan 15 '15 15:01

Tom Kraina


3 Answers

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.

like image 73
Rob Avatar answered Nov 05 '22 22:11

Rob


If you are stopped in Swift code, paste this line into the debugger console (after the (lldb) prompt) and press enter to print the hierarchy of the root view controller:

po UIWindow.value(forKeyPath: "keyWindow.rootViewController._printHierarchy")!

If you are stopped in Objective-C code or assembly code, use this line instead:

po [UIWindow valueForKeyPath:@"keyWindow.rootViewController._printHierarchy"]
like image 13
rob mayoff Avatar answered Nov 05 '22 21:11

rob mayoff


The options that have already been posted here are great, another option (similar to this answer), if you absolutely need to be using the Swift lldb context (meaning you don't want to pass -l objc, is you can call performSelector:

Which is bridged to Swift like this:

func perform(_ aSelector: Selector!) -> Unmanaged<AnyObject>!

For this case you would call it like this:

po UIApplication.shared.keyWindow!.rootViewController!.perform("_printHierarchy")!.takeUnretainedValue()
like image 2
Keith Smiley Avatar answered Nov 05 '22 21:11

Keith Smiley