ios - ¿Cómo usar_printHierarchy en la consola LLDB con Swift?
ios8 xcode6 (7)
Después de algunas investigaciones, descubrí que es solo una cuestión de exponer esta API en particular (copiada de los encabezados de tiempo de ejecución de iOS ) en el encabezado puente del proyecto para que esté disponible para Swift:
@interface UIViewController (Debugging)
+ (id)_printHierarchy;
@end
Durante el tiempo de ejecución, este método de clase se puede llamar de la siguiente manera:
(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
... imprimiendo la jerarquía del controlador de vista. Tenga en cuenta que el método solo debe llamarse en el hilo principal (UI).
Apple agregó un ayudante privado _printHierarchy
en iOS8 que se puede usar en la consola LLDB:
po [[[UIWindow keyWindow] rootViewController] _printHierarchy]
que imprime toda la jerarquía del controlador de vista en forma de texto.
Esto solo funciona si está depurando código en Objective C. Sin embargo, en Swift, esto no funciona:
(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]
^
,
Un uso equivalente en Swift tampoco funciona:
po UIApplication.sharedApplication().keyWindow!.rootViewController!._printHierarchy
termina con un error (probablemente porque _printHierarchy
es una propiedad privada):
(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
^ ~~~~~~~~~~~~~~~
La pregunta es: ¿Cómo imprimir la jerarquía del controlador de vista en Swift? ¿O hay una manera de usar ObjC en la consola LLDB incluso en proyectos Swift?
Las opciones que ya se han publicado aquí son excelentes, otra opción (similar a esta respuesta ), si es absolutamente necesario que esté usando el contexto Swift lldb (lo que significa que no quiere pasar -l objc
, es que puede llamar a performSelector:
Que se une a Swift de esta manera:
func perform(_ aSelector: Selector!) -> Unmanaged<AnyObject>!
Para este caso lo llamarías así:
po UIApplication.shared.keyWindow!.rootViewController!.perform("_printHierarchy")!.takeUnretainedValue()
Parece que, dado que este es un ayudante "privado", de alguna manera no está expuesto a Swift. Tampoco es accesible desde dentro de Objective-C, es decir,
UIViewController* vc = // Assign view controller
[vc _printHierarchy];
resulta en un error de tiempo de compilación. Sin embargo, lo que podría funcionar es usar NSSelectorFromString
dentro de un encabezado puente, por ejemplo
-(void) printHierarchyWithVC:(UIViewController*) vc
{
[vc performSelector: NSSelectorFromString(@"_printHierarchy")];
}
Una vez que se haya definido, puede llamar a printHierarchyWithVC
desde Swift.
Recomiendo usar expr -l objc++ -O -- [UIViewController _printHierarchy]
en la consola, ya que imprimirá la jerarquía de vista completa en forma de texto, lo que me parece mucho más útil que UIWindow.valueForKeyPath ... Tenga en cuenta que no necesita para agregar po
para imprimir la jerarquía, solo use como es.
Esto funciona para mí, Xcode 8 / swift 3, aunque creo que el mismo comando también funciona en versiones anteriores de Xcode porque parece que es el objetivo C.
salida de ejemplo de este comando:
(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>
Si se detiene en el código Swift, pegue esta línea en la consola del depurador (después del (lldb)
) y presione Intro para imprimir la jerarquía del controlador de vista raíz:
po UIWindow.value(forKeyPath: "keyWindow.rootViewController._printHierarchy")!
Si está detenido en el código de Objective-C o en el código de ensamblaje, use esta línea en su lugar:
po [UIWindow valueForKeyPath:@"keyWindow.rootViewController._printHierarchy"]
Usted señala cómo se muestra la jerarquía del controlador de vista con:
po [[[UIWindow keyWindow] rootViewController] _printHierarchy]
Entonces dices:
Esto funciona solo si está depurando código en Objective C. Sin embargo, en Swift, esto no funciona.
En realidad, esto depende un poco de cómo pause la ejecución de su programa Swift. El problema es que el comando de expression
(que usa po
) usará expresiones Swift en marcos Swift, y expresiones Objective-C en marcos Objective-C. Por lo tanto, esto significa que el comportamiento del po
varía dependiendo de cómo se detiene la ejecución:
Por ejemplo, puede presionar el botón "pausar" mientras se ejecuta la aplicación:
Si hace esto, podrá utilizar la sintaxis
po
anterior con la expresión Objective-C sin incidentes.Si, por otro lado, establece un punto de interrupción dentro de su código Swift, estará en un marco Swift cuando llegue al
(lldb)
. Pero puede decirle explícitamente al comando deexpression
que desea usar la sintaxis de Objective-C con la opción-l
(o--language
):expr -l objc++ -O -- [[[UIWindow keyWindow] rootViewController] _printHierarchy]
Esta capacidad de especificar el idioma en el comando expr
se describe en el video de la WWDC 2014 Advanced Swift Debugging en LLDB .