2015-01-15 4 views
16

Apfel hat ein private helper _printHierarchy in iOS8, die in LLDB Konsole verwendet werden können:Wie verwenden Sie _printHierarchy in LLDB-Konsole mit Swift?

po [[[UIWindow keyWindow] rootViewController] _printHierarchy] 

, die die ganze View-Controller-Hierarchie in Textform ausgedruckt.

Dies funktioniert nur, wenn Sie Code auf Objective C. In Swift debuggen, aber das funktioniert nicht:

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

Eine äquivalente Verwendung in Swift funktioniert auch nicht:

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

endet mit einem Fehler auf (wahrscheinlich, weil _printHierarchy ein Privateigentum ist):

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

Die Frage ist: Wie kann man die View Controller Hierarchie in Swift ausdrucken? Oder gibt es eine Möglichkeit, ObjC in der LLDB-Konsole auch in Swift-Projekten zu verwenden?

Antwort

42

Sie darauf hinweisen, wie man die View-Controller-Hierarchie zeigt mit:

po [[[UIWindow keyWindow] rootViewController] _printHierarchy] 

Sie sagen dann:

Dies funktioniert nur, wenn Sie Code auf Objective C. In Swift debuggen jedoch das funktioniert nicht.

Eigentlich hängt das ein wenig davon ab, wie Sie die Ausführung Ihres Swift-Programms anhalten. Das Problem ist, dass der Befehl expression (der po verwendet) Swift-Ausdrücke in Swift-Rahmen und Objective-C-Ausdrücke in Objective-C-Rahmen verwenden wird.So bedeutet dies, dass das po Verhalten variiert je nachdem, wie die Ausführung pausiert:

  • können Sie zum Beispiel die Taste „Pause“ Taste, während die App läuft:

    pause

    Wenn Wenn Sie dies tun, können Sie die obige po-Syntax mit dem Objective-C-Ausdruck ohne Zwischenfälle verwenden.

  • Wenn Sie andererseits einen Haltepunkt in Ihrem Swift-Code festlegen, befinden Sie sich in einem Swift-Rahmen, wenn Sie zur Eingabeaufforderung (lldb) gelangen. Aber Sie können den expression Befehl explizit sagen, dass Sie die Objective-C-Syntax mit der -l (oder --language) Option verwenden mögen:

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

Diese Fähigkeit, die Sprache in dem expr Befehl angegeben wird diskutiert in WWDC 2014 Video Advanced Swift Debugging in LLDB.

+0

Hmm, habe ich versucht, und Ich habe meine Frage aktualisiert mit einem Fehler werde ich in der Konsole. –

+0

@TomKraina Wenn Sie einen Breakpoint im Swift-Code verwenden, befinden Sie sich in einem Swift-Frame und "po" erwartet Swift-Ausdruck. Wenn Sie jedoch während der Ausführung des Swift-Programms nur die Pause-Taste drücken (was ich oft tue), sind Sie höchstwahrscheinlich nicht in einem Swift-Frame, wenn Sie die Eingabeaufforderung "(lldb)" erhalten Der Objective-C-Ausdruck ist in Ordnung. Glücklicherweise können Sie, wenn Sie die App im Swift-Frame anhalten, explizit die Option '--language' (oder' -l') angeben, um anzugeben, dass der Objective-C-Ausdruck interpretiert werden soll, selbst wenn Sie sich im Swift-Frame befinden . Siehe überarbeitete Antwort. – Rob

+1

Das ist cool! Ich wusste nicht, dass du eine Sprache in "lldb" angeben kannst! –

1

Es scheint, als wäre es ein "privater" Helfer, der Swift irgendwie nicht ausgesetzt ist. Es ist auch nicht innerhalb von Objective-C zugänglich, d. H.

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

führt zu einem Kompilierzeitfehler. Was jedoch funktionieren könnte, ist die Verwendung von NSSelectorFromString in einem Überbrückungs-Header, z.

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

Sobald dies definiert ist, können Sie printHierarchyWithVC von Swift nennen.

1

Nach einigen Recherchen fand ich heraus, dass es nur eine Frage der diese spezielle API aussetzt (kopiert von iOS runtime headers) in Brückenkopf des Projekts, so dass es zu Swift verfügbar wird:

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

Während der Laufzeit dieser Methode Klasse kann wie folgt aufgerufen werden:

(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 

... die View-Controller-Hierarchie auszudrucken. Beachten Sie, dass die Methode nur für den Hauptthread aufgerufen werden muss.

+0

Das in Xcode nicht funktioniert 7. – Boon

11

Wenn Sie in Swift Code angehalten werden, füge diese Zeile in die Debugger Konsole (nach den (lldb) prompt) ein und drücken Sie die Hierarchie der Wurzel View-Controller drucken:

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

Wenn Sie bleibt Objective-C-Code oder Assembler-Code, diese Zeile statt:

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

Können Sie bitte etwas Kontext um Ihre Antwort hinzufügen? – winhowes

+1

Warum? Die Frage lautete "Wie benutze ich _printHierarchy in der LLDB-Konsole mit Swift?" Und eine Antwort ist der Befehl, den ich zeigte. –

0

ich expr -l objc++ -O -- [UIViewController _printHierarchy] in der Konsole empfehlen, da sie die vollständige Ansicht Hierarchie in Textform auszudrucken werden, die ich wesentlich nützlicher als UIWindow.value gefunden ForKeyPath ... Beachten Sie, dass Sie po nicht hinzufügen müssen, um die Hierarchie zu drucken, verwenden Sie einfach, wie es ist.

Dies funktioniert für mich, Xcode 8/swift 3 obwohl ich glaube, die denselben Befehl funktioniert auch in früheren Versionen von Xcode auch, weil es sieht aus wie es Ziel C. ist

Beispiel Ausgabe dieses Befehls:

(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

Nach Chisel Installation können Sie einfach die folgenden Schritte aus und more:

(lldb) pvc

0

Die Optionen, die bereits hier gepostet wurden, sind groß, eine weitere Option (ähnlich this answer), wenn Sie unbedingt den Swift LLDB Zusammenhang mit benötigen werden (das heißt, Sie wollen nicht -l objc passieren, ist man nennen kann performSelector:

Welche Swift wie diese überbrückt wird:

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

Für diesen Fall, dass Sie es so nennen würde:

po UIApplication.shared.keyWindow!.rootViewController!.perform("_printHierarchy")!.takeUnretainedValue() 
Verwandte Themen