¿Cómo establecer un punto de interrupción condicional en Xcode basado en una propiedad de cadena de objeto?

90

Estoy buscando poder hacer que el depurador se rompa cuando alcance una coincidencia de cadena en particular. Como ejemplo, podría tener algo como esto:

Foo myObj = [self gimmeObj];

myObjpodría tener una propiedad llamada name. Quiero que el depurador se detenga en la tarea cuando

[myObj.name isEqualToString:@"Bar"];

¿Cómo puedo configurar mi punto de interrupción condicional en Xcode para hacer eso?

Coocoo4Cocoa
fuente

Respuestas:

184

Puede establecer un punto de interrupción condicional en Xcode configurando el punto de interrupción normalmente, luego haga clic con la tecla Control y haga clic en él y seleccione Editar punto de interrupción (elija Ejecutar -> Mostrar -> Puntos de interrupción).

En la entrada del punto de interrupción, hay una columna Condición.

Ahora bien, hay varias cuestiones a tener en cuenta para la afección. En primer lugar, gdb no comprende la sintaxis de puntos, por lo que en lugar de myObj.name, debe usar [myObj name] (a menos que el nombre sea un ivar).

A continuación, como con la mayoría de las expresiones en gdb, debe indicarle el tipo de resultado devuelto, a saber, "BOOL". Así que establezca una condición como:

(BOOL)[[myObj name] isEqualToString:@"Bar"]

A menudo, es más fácil hacer esto en el código agregando temporalmente código como:

if ( [myObj.name isEqualToString:@"Bar"] ) {
    NSLog( @"here" );
}

y luego establecer el punto de interrupción en NSLog. Entonces su condición puede ser arbitrariamente compleja sin tener que preocuparse por lo que gdb puede y no puede analizar.

Peter N Lewis
fuente
11
Excepto que al alterar su código corre el riesgo de olvidar eliminar su registro o alterar su comportamiento
Pål Brattberg
3
Es verdad. A menudo mitigo esto agregando "NYI" (aún no implementado) a la cadena, y luego mi búsqueda de cheques de pre-lanzamiento para NYI lo detectará.
Peter N Lewis
17
Para que esto funcione, tuve que poner (bool) en mayúsculas como (BOOL), probablemente una cosa LLDB.
Wex
1
bool no funcionó para mí en GDB, tuve que usar BOOL o int. La diferencia se explica aquí stackoverflow.com/a/544250/725871 .
Chaosphere2112
2
No puede ponerlo en código si tiene un error de juego una vez cada 200 que finalmente ha aparecido, y ahora necesita hacer un punto de interrupción condicional. Detener el programa para alterar el código no es una opción.
Almo
17

Así es como se usa con los puntos de interrupción condicionales de XCode lldb.

Primero, haga doble clic en el punto de ruptura (o haga clic derecho edit breakpoint), puede ver un cuadro de diálogo emergente.

ingrese la descripción de la imagen aquí

Esto es lo que significan esas opciones:

  1. Condición : el punto de interrupción solo se disparará bajo esta condición.
  2. Ignorar : la cantidad de veces que la condición debe cumplir antes de disparar el punto de interrupción
  3. Acción : Acción que se ejecuta después de que se rompe el punto de interrupción.
  4. Opciones : continuar automáticamente después de evaluar las acciones

He aquí un resumen. Para el ejemplo anterior en la imagen, significa que cuando la variable buildingIdes igual a 13, rompa aquí. Si agrego el tiempo de ignorar a 1, se ignorará la primera vez cuando buildingIdsea ​​igual a 13 y se interrumpirá en la segunda vez que se cumpla la condición.

Para las acciones, cuando presione agregar acciones, habrá una lista de opciones. Por lo general, lo que hago es usar Debugger Command popara imprimir variables que necesito verificar y creo que hay mejores formas de usar las acciones que yo.

Parece que tiene que volver a compilar y ejecutar la aplicación si cambia las condiciones en tiempo de ejecución

Nuynait
fuente
Probablemente porque la pregunta era acerca de detenerse en un punto de ruptura basado en un valor de cadena [yo no era el votante en contra]
ZS
1
Gracias, muy útil. Esta respuesta merece más votos.
andreskwan
7

No estoy seguro de si esto funcionará, pero puede intentar establecer un punto de interrupción en esa línea de código, abrir la consola del depurador (Cmd + Shift + R) y escribir

condition N (int)[[myObj name] isEqualToString:@"Bar"]

Donde N se reemplaza por el número del punto de interrupción (un número entero).

Adam Rosenfield
fuente
2

Si mutas myObj.name usando el setter, puedes agregar un punto de interrupción simbólico -[MyObjClass setName:]desde la Consola del depurador o desde el menú Ejecutar-> Administrar puntos de interrupción- > Agregar punto de interrupción simbólico en Xcode. Si no es así (¿por qué no? Probablemente no debería modificar la variable de instancia directamente, excepto en el inicializador designado o desbloqueo), puede establecer un punto de observación en gdb (use la Consola del depurador en Xcode una vez que el depurador se esté ejecutando). Esta página explica cómo. No creo que Xcode exponga una interfaz de usuario para establecer puntos de observación sin usar la consola de depuración.

Barry Wark
fuente
0

En ocasiones, cuando se trabaja con Frameworks (depuración de compilaciones) y se necesita poner un punto de interrupción en cierto archivo / ubicación que es difícil de navegar o que no se expone públicamente en un framework en desarrollo. Una opción es escribir una clase auxiliar para activar puntos de interrupción condicionales y facilitar el paso de entrada / salida.

- (void)invokeFrameworkMethod {
    ...
    [DebugConditionalBreakPointHelper breakPointCondition:YES comment:@"from invokeFrameworkMethod."];
    ...
}

Declaración de encabezado en marco en desarrollo.

#import <Foundation/Foundation.h>

@interface DebugConditionalBreakPointHelper : NSObject
+ (void)breakPointCondition:(BOOL)enabled comment:(NSString *)comment;
@end

Y archivo de implementación:

#import "DebugConditionalBreakPointHelper.h"

@implementation DebugConditionalBreakPointHelper
+ (void)breakPointCondition:(BOOL)enabled comment:(NSString *)comment {
    if (enabled)
    {
        NSLog(@"Triggerred Conditional Break Point. Comment: %@");
    }
}
@end
lal
fuente