15

I'm trying to enable/disable parts of my code based on whether or not the code be being run via USB/Xcode (debug), or in production mode downloaded from the app store (release). I'm aware of checking if it is running in DEBUG or RELEASE mode like this:

enter image description here

#ifdef DEBUG

// Stuff for debug mode

#else

// Stuff for release mode

#endif

but the problem is that an obvious loop-hole I see is you can change the Build Configuration for the 'Run' build scheme from 'Debug' to 'Release'. A better way would be if I can simply detect if it is running from Xcode or not. I haven't found a way to check for this.

Is there a way to check if an iOS app is running from Xcode or not?

Kevin_TA
  • 4,575
  • 13
  • 48
  • 77
  • Your question is valid - I can imagine that you would like to detect whether a DEBUG app is running with XCode connected or not. But your reasons are dubious - why would you ever like to change the Build Configuration in that way? – fishinear Dec 02 '14 at 16:12
  • Are you asking why one would change the 'Run' Build Configuration from the default 'Debug' to 'Release'? I've found it to be good practice before submitting an app to the app store as I've seen bugs pop up in Release mode that don't exist in Debug mode. – Kevin_TA Dec 02 '14 at 16:27
  • The Release build does not allow XCode to connect to the app - in my case at least. Is that different for you? – fishinear Dec 02 '14 at 16:37

1 Answers1

27

You can check if a debugger is attached (probably, but not definitely, Xcode) using sysctl. Here's how HockeyApp does it:

#include <Foundation/Foundation.h>
#include <sys/sysctl.h>

/**
 * Check if the debugger is attached
 *
 * Taken from https://github.com/plausiblelabs/plcrashreporter/blob/2dd862ce049e6f43feb355308dfc710f3af54c4d/Source/Crash%20Demo/main.m#L96
 *
 * @return `YES` if the debugger is attached to the current process, `NO` otherwise
 */
- (BOOL)isDebuggerAttached {
  static BOOL debuggerIsAttached = NO;

  static dispatch_once_t debuggerPredicate;
  dispatch_once(&debuggerPredicate, ^{
    struct kinfo_proc info;
    size_t info_size = sizeof(info);
    int name[4];

    name[0] = CTL_KERN;
    name[1] = KERN_PROC;
    name[2] = KERN_PROC_PID;
    name[3] = getpid(); // from unistd.h, included by Foundation

    if (sysctl(name, 4, &info, &info_size, NULL, 0) == -1) {
      NSLog(@"[HockeySDK] ERROR: Checking for a running debugger via sysctl() failed: %s", strerror(errno));
      debuggerIsAttached = false;
    }

    if (!debuggerIsAttached && (info.kp_proc.p_flag & P_TRACED) != 0)
      debuggerIsAttached = true;
  });

  return debuggerIsAttached;
}
Steven Fisher
  • 44,462
  • 20
  • 138
  • 192
  • Note you need to #include for getpid() – Ryan Feb 05 '17 at 16:11
  • @Ryan Only if you're not including Foundation, which you probably are if you're using GCD, object syntax, BOOL including YES and NO. But I'll note the dependance on Foundation. :) – Steven Fisher Feb 06 '17 at 20:03
  • There, that should work. Thanks. – Steven Fisher Feb 06 '17 at 20:10
  • @Stephen Fisher, yea you're right. I was using only C and no GCD, so found I needed unistd.h, but as-written, yea, you don't need it. – Ryan Feb 08 '17 at 18:35
  • I should probably edit the code to be consistent about `BOOL` vs. `bool`. Including submitting a patch if it's still mixed up in HockeyApp. But noting which header and importing Foundation should do for now – Steven Fisher Feb 08 '17 at 18:53
  • There is the Swift solution: https://stackoverflow.com/a/33177600/6197314 – SwiftyFinch Feb 05 '23 at 09:30