Detectando si la aplicación de iOS se ejecuta en el depurador

Configuré mi aplicación para enviar salida de depuración a la consola o un archivo de registro. Ahora, me gustaría decidir con el código si

  • se ejecuta en el depurador (o simulador) y tiene una ventana de consola en la que me gustaría leer el resultado directamente o si
  • no hay ventana de consola y, por lo tanto, la salida debe redirigirse a un archivo.

¿Hay alguna manera de determinar si la aplicación se ejecuta en el depurador?

Hay una función de Apple para detectar si un progtwig se está depurando en el Technical Q & A 1361 ( entrada en la biblioteca Mac y entrada en la biblioteca iOS , son idénticas).

Código de la sección de preguntas y respuestas técnicas:

#include  #include  #include  #include  #include  static bool AmIBeingDebugged(void) // Returns true if the current process is being debugged (either // running under the debugger or has a debugger attached post facto). { int junk; int mib[4]; struct kinfo_proc info; size_t size; // Initialize the flags so that, if sysctl fails for some bizarre // reason, we get a predictable result. info.kp_proc.p_flag = 0; // Initialize mib, which tells sysctl the info we want, in this case // we're looking for information about a specific process ID. mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = getpid(); // Call sysctl. size = sizeof(info); junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0); assert(junk == 0); // We're being debugged if the P_TRACED flag is set. return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); } 

También preste atención a esta nota al final de la sesión de preguntas y respuestas:

Importante: Debido a que la definición de la estructura kinfo_proc (en ) está condicionada por __APPLE_API_UNSTABLE , debe restringir el uso del código anterior a la comstackción de depuración de su progtwig.

Es posible indicar al depurador que establezca variables de entorno cuando inicia un proceso que está por depurar. Esto se puede hacer en Xcode yendo a la opción de menú Producto-> Editar esquema. Luego, bajo la pestaña Argumentos del esquema de Depuración, agregue una nueva variable de entorno. La variable debe llamarse “depurador” con el valor “verdadero”. A continuación, se puede utilizar el siguiente fragmento de código para determinar si el depurador inició su proceso:

 NSDictionary* env = [NSProcessInfo processInfo].environment; if ([env[@"debugger"] isEqual:@"true"]) { NSLog(@"debugger yes"); } else { NSLog(@"debugger no"); } 

Siempre es bueno tener diferentes soluciones, así que aquí están mis dos centavos:

La idea es comprobar el NSLog stderr (aquí es donde se imprime NSLog ). Esta solución ha estado funcionando confiablemente desde al menos iOS 4 y sigue haciéndolo en iOS 9, tanto en el simulador como en el dispositivo.

 #import  #import  #if TARGET_IPHONE_SIMULATOR #import  #else // Not sure why  is missing on the iPhoneOS.platform. // It's there on iPhoneSimulator.platform, though. We need it for D_DISK, only: #if ! defined(D_DISK) #define D_DISK 2 #endif #endif BOOL isDebuggerAttatchedToConsole(void) { // We use the type of the stderr file descriptor // to guess if a debugger is attached. int fd = STDERR_FILENO; // is the file handle open? if (fcntl(fd, F_GETFD, 0) < 0) { return NO; } // get the path of stderr's file handle char buf[MAXPATHLEN + 1]; if (fcntl(fd, F_GETPATH, buf ) >= 0) { if (strcmp(buf, "/dev/null") == 0) return NO; if (strncmp(buf, "/dev/tty", 8) == 0) return YES; } // On the device, without attached Xcode, the type is D_DISK (otherwise it's D_TTY) int type; if (ioctl(fd, FIODTYPE, &type) < 0) { return NO; } return type != D_DISK; } 

La solución más simple en realidad es

 _isDebugging = isatty(STDERR_FILENO); 

No es exactamente lo mismo que decir si la aplicación se está ejecutando en el depurador, pero lo suficientemente bueno (¿incluso mejor?) Para determinar si el registro debe escribirse en el disco.

Para mí, esta pieza de código rápido funciona perfectamente:

 func isDebuggerAttached() -> Bool { return getppid() != 1 } 

Suelo buscar una solución mucho más simple; es el binario comstackdo con optimizaciones?

Una versión de depuración no está optimizada y los registros son agradables. Una versión de lanzamiento debería tener optimizaciones y no tantos registros. Puede verificar esto con el símbolo __OPTIMIZE__ .

Para el registro utilizo esta configuración para logg- funciones :

 #ifdef __OPTIMIZE__ #define CWLog(...) #define CWLogDebug(...) #define CWLogInfo(...) #else #define CWLog(...) NSLog(__VA_ARGS__) #define CWLogDebug( s, ... ) NSLog( @"DEBUG <%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] ) #ifndef LOG_INFO #define CWLogInfo(...) #else #define CWLogInfo( s, ... ) NSLog( @"INFO <%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] ) #endif #endif #define CWLogWarning( s, ... ) NSLog( @"WARNING <%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] ) #define CWLogError( s, ... ) NSLog( @"ERROR <%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] ) 

¿Por qué no usar el bloque de comstackción condicional en Swift?

  #if DEBUG // Do something. #endif 

¿Alguna objeción?

Puede definir si desea una constante de tiempo de ejecución

 #if DEBUG public let IS_RUNNING_IN_DEBUGGER: Bool = true #else public let IS_RUNNING_IN_DEBUGGER: Bool = false #endif 

El mismo enfoque se puede usar en Objc y más.