检测iOS应用程序是否在debugging器中运行

我将我的应用程序设置为将debugging输出发送到控制台或日志文件。 现在,我想在代码中决定是否

  • 它在debugging器(或模拟器)中运行,因此有一个控制台窗口,我想直接读取输出或如果
  • 没有控制台窗口,因此,输出应该被redirect到一个文件。

有没有一种方法来确定应用程序是否在debugging器中运行?

有一个苹果公司的function来检测程序是否在技术问答1361 ( 在Mac库中 input和在iOS库中input ;它们是相同的)中被debugging。

技术问答代码:

#include <assert.h> #include <stdbool.h> #include <sys/types.h> #include <unistd.h> #include <sys/sysctl.h> 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 ); } 

问答结束时还要注意这个注意事项:

重要说明:因为kinfo_proc结构(在<sys/sysctl.h> )的定义是以kinfo_proc为条件的,所以应该限制使用上面的代码到程序的debugging版本中。

可以指示debugging器在启动要debugging的进程时设置环境variables。 这可以通过转到菜单项Product-> Edit Scheme在Xcode中完成。 然后在Debugscheme的Arguments选项卡下添加一个新的环境variables。 应将该variables命名为“debugging器”,其值为“true”。 然后,可以使用以下代码片断来确定debugging器是否启动了您的进程:

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

总是很好有不同的解决scheme,所以这里是我的两分钱:

这个想法是检查stderr文件句柄(这是NSLog打印到的地方)。 这个解决scheme至less可以在iOS 4下稳定运行,并且在模拟器和设备上都可以继续使用。

 #import <sys/ioctl.h> #import <sys/param.h> #if TARGET_IPHONE_SIMULATOR #import <sys/conf.h> #else // Not sure why <sys/conf.h> 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; } 

我通常会寻求更简单的解决scheme。 是与优化编译的二进制文件?

debugging版本没有优化,日志很好。 发布版本应该有优化,而不是多个日志。 你可以用__OPTIMIZE__符号来检查。

对于日志logging,我使用这个设置的日志function

 #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__] ) 

对我来说,这段快速代码完美地工作:

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

最简单的解决scheme实际上是

 _isDebugging = isatty(STDERR_FILENO); 

这与判断应用程序是否在debugging器下运行并不完全相同,但足够好(甚至更好?)以确定日志是否应写入磁盘。