2015-01-15 22 views
16

蘋果增加,可以在控制檯LLDB中使用的private helper _printHierarchy in iOS8如何在使用Swift的LLDB控制檯中使用_printHierarchy?

po [[[UIWindow keyWindow] rootViewController] _printHierarchy] 

打印出的文本形式的整體視圖控制器層次結構。

這僅適用,如果你正在調試的目的C.在斯威夫特的代碼,但是,這並不工作:

(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] 
             ^
              , 

在雨燕等同使用無法正常工作或:

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

結束了一個錯誤(可能是因爲_printHierarchy是私人財產):

(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 
                  ^~~~~~~~~~~~~~~~ 

問題是:如何在Swift中打印視圖控制器層次結構?或者有沒有一種方法,即使在Swift項目中,如何在LLDB控制檯中使用ObjC?

回答

42

你點了怎麼一個顯示了視圖控制器層次:

po [[[UIWindow keyWindow] rootViewController] _printHierarchy] 

你然後說:

這隻有你在目標C調試代碼在斯威夫特,但是,這不起作用。

實際上,這取決於你如何暫停Swift程序的執行。問題是expression命令(其中po使用)將在Swift框架中使用Swift表達式,在Objective-C框架中使用Objective-C表達式。因此,這意味着po行爲的變化取決於執行如何暫停:

  • 可以,例如,按「暫停」按鈕,應用程序運行時:

    pause

    如果你這樣做,你就可以在Objective-C表達式中使用上面的po語法,而不會發生任何事情。

  • 另一方面,如果您在Swift代碼中設置了一個斷點,當您進入(lldb)提示符時,您將會進入Swift框架。但是你可以明確地告訴expression命令要使用Objective-C的語法與-l(或--language)選項:

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

指定在expr命令的語言這種能力在討論WWDC 2014視頻Advanced Swift Debugging in LLDB

+0

嗯工作,我已經試過了,並我更新了我的questi在控制檯中出現錯誤。 – 2015-02-19 15:26:32

+0

@TomKraina如果您在Swift代碼中使用斷點,那麼您處於Swift框架中,因此'po'需要Swift表達式。但是,如果你在Swift程序運行時(這是我經常做的),你只需點擊暫停按鈕,當你得到'(lldb)'提示符時,你很可能不會在Swift框架中,因此Objective-C表達式很好。幸運的是,如果您在Swift框架中暫停應用程序,仍然可以明確提供'--language'選項(或'-l'選項)來指定即使您處於Swift框架中,也應該解釋Objective-C表達式。看修改後的答案。 – Rob 2015-02-19 19:00:21

+1

太酷了!我不知道你可以在'lldb'中指定一種語言! – 2015-02-20 16:31:36

1

看起來,因爲這是一個「私人」幫手,它不知道怎麼暴露給Swift。它也不能從Objective-C中訪問,即

UIViewController* vc = // Assign view controller 
[vc _printHierarchy]; 

導致編譯時錯誤。然而,可能有效的是在橋頭中使用NSSelectorFromString,例如,

-(void) printHierarchyWithVC:(UIViewController*) vc 
{ 
    [vc performSelector: NSSelectorFromString(@"_printHierarchy")]; 
} 

一旦定義了這個,你可以從Swift調用printHierarchyWithVC

1

經過一番研究,我發現,這只是一個項目的橋接報揭露這個特殊的API(從iOS runtime headers複製)的物質,使其成爲提供給斯威夫特:

@interface UIViewController (Debugging) 
+ (id)_printHierarchy; 
@end 

在運行期間,該類方法可以調用如下:

(lldb) po UIViewController._printHierarchy() as NSString 
<UINavigationController 0x7f8a50733c70>, state: appearing, view: <UILayoutContainerView 0x7f8a5064def0> 
    | <MyApp.RootViewController 0x7f8a507341f0>, state: appearing, view: <UIView 0x7f8a5056d860> not in the window 

...打印出視圖控制器層次結構。請注意,只能在主(UI)線程上調用該方法。

+0

這並不在Xcode 7 – Boon 2015-10-19 01:58:48

11

如果您在銀行代碼停了下來,粘貼線進入調試器控制檯(後(lldb)提示),然後按ENTER鍵打印的根視圖控制器的層次:

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

如果你停在Objective-C代碼或彙編代碼,使用該行:

po [UIWindow valueForKeyPath:@"keyWindow.rootViewController._printHierarchy"] 
+1

你可以在你的答案中添加一些上下文嗎? – winhowes 2016-05-11 00:12:11

+1

爲什麼?問題是「如何在帶有Swift的LLDB控制檯中使用_printHierarchy?」,答案就是我展示的命令。 – 2016-05-11 00:15:47

0

我建議在控制檯中使用expr -l objc++ -O -- [UIViewController _printHierarchy],因爲它會打印出的文本形式的完整視圖層次,我發現顯著更有用比UIWindow.value ForKeyPath ...請注意,您不需要添加po來打印層次結構,只需按原樣使用即可。

這個工作對我來說,Xcode中8/3迅疾雖然我認爲同樣的命令也適用於早期版本的Xcode的一點,因爲它看起來是客觀C.從這個命令的輸出

例如:

(lldb) expr -l objc++ -O -- [UIViewController _printHierarchy] 

<MyProject.SwipeController 0x102213590>, state: disappeared, view: <UIView 0x102239ff0> not in the window 
    + <MyProject.CameraViewController 0x102215680>, state: disappeared, view: <UIView 0x102422fd0> not in the window, presented with: <_UIFullscreenPresentationController 0x102219c60> 
    | + <MyProject.MapViewController 0x102214820>, state: appeared, view: <UIView 0x10bf52fe0>, presented with: <_UIFullscreenPresentationController 0x10fd1f890> 
    | | | <MyProject.MapPlaceCollectionViewController 0x10bf54680>, state: appeared, view: <UICollectionViewControllerWrapperView 0x1022438d0> 
0

安裝Chisel以後,就可以執行下列操作和more

(lldb) pvc

0

已經被張貼在這裏的選項是偉大的,另一種選擇(類似於this answer),如果你絕對需要使用雨燕LLDB上下文(意思是你不希望傳遞-l objc,是你可以叫performSelector:

這是橋接斯威夫特這樣的:

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

對於這種情況,你會這樣稱呼它:

po UIApplication.shared.keyWindow!.rootViewController!.perform("_printHierarchy")!.takeUnretainedValue() 
相關問題