294

As the question states, I would mainly like to know whether or not my code is running in the simulator, but would also be interested in knowing the specific iphone version that is running or being simulated.

EDIT: I added the word 'programmatically' to the question name. The point of my question is to be able to dynamically include / exclude code depending on which version / simulator is running, so I'd really be looking for something like a pre-processor directive that can provide me this info.

Haroldo Gondim
  • 7,725
  • 9
  • 43
  • 62
Jeffrey Meyer
  • 5,410
  • 7
  • 30
  • 27
  • I'm not sure a pre-processor directive is dynamic (though it might be what you were looking for anyway). The directive means that you actually knew, when you built it, where it was going to wind up running. – WiseOldDuck Apr 15 '16 at 19:18
  • As I know my target is only a new iPhone or Simulator, I like `__x86_64__` ( iPhone simulator ) and `__arm64__` ( iPhone device ) – rustyMagnet Oct 01 '20 at 10:58

21 Answers21

366

Already asked, but with a very different title.

What #defines are set up by Xcode when compiling for iPhone

I'll repeat my answer from there:

It's in the SDK docs under "Compiling source code conditionally"

The relevant definition is TARGET_OS_SIMULATOR, which is defined in /usr/include/TargetConditionals.h within the iOS framework. On earlier versions of the toolchain, you had to write:

#include "TargetConditionals.h"

but this is no longer necessary on the current (Xcode 6/iOS8) toolchain.

So, for example, if you want to check that you are running on device, you should do

#if TARGET_OS_SIMULATOR
    // Simulator-specific code
#else
    // Device-specific code
#endif

depending on which is appropriate for your use-case.

Jeremy Huddleston Sequoia
  • 22,938
  • 5
  • 78
  • 86
Airsource Ltd
  • 32,379
  • 13
  • 71
  • 75
  • 1
    Thanks. I agree with you this is a more specific version of your original question. If yours had come up in my original search, I wouldn't have even needed to ask. – Jeffrey Meyer Jan 19 '09 at 21:06
  • Yes, I appreciate that it doesn't show up easily in a search - I was just referencing it as a duplicate so that people could read comments in both places. – Airsource Ltd Jan 22 '09 at 18:11
  • 5
    Be careful with these definitions. When you compile code with menu item 'Project > Set Active SDK > Simulator…', as TARGET_IPHONE_SIMULATOR as TARGET_OS_IPHONE variables are both defined! So the only right way to separate logic is pointed out below by Pete (Thanks dude). – Vadim Jan 24 '09 at 02:05
  • Correct, but when you compile for device, TARGET_IPHONE_SIMULATOR is not set, so why not just switch on that? Switching on __i386__ relies on the toolchain defs, and will be invalid if compiling on a non-x86 platform (not currently possibly, of course). – Airsource Ltd Jan 26 '09 at 12:31
  • 5
    Watch the #if and #ifdef difference. For me it was the cause of incorrect behavior. – Anton Jan 09 '10 at 09:32
  • as said here: http://stackoverflow.com/questions/3742525/target-os-iphone-and-applicationtests it is not true for static libraries – cyrilchampier Aug 09 '12 at 08:13
  • 7
    Perhaps the need to include TargetConditionals has been obviated since this was written, but just wanted to note that #if TARGET_IPHONE_SIMULATOR works without including TargetConditionals.h now. – dmur Mar 04 '14 at 23:34
  • Wouldn't it better to use the regular `if` instead of the pre-processor `#if` so that you have to potential to get compiler errors in both control paths? The pre-processor `#if` doesn't compile the branch that you're currently not targeting. You wouldn't want to have a false sense of accomplishment when all your code works on the simulator, but your real device branch is broken. – JoJo Jul 29 '15 at 23:55
  • You may be #if-ing code that doesn't actually compile on one platform or the other, but yes, you could use if. Not sure how this helps with the false sense of achievement, you would still need to test it on both platforms! – Airsource Ltd Jul 30 '15 at 09:10
  • Why the parentheses ( ) around TARGET_OS_SIMULATOR? – Dimitris Apr 28 '16 at 22:06
  • I needed the include in an Obj-C file for iOS 9 using Xcode 7. Hmm. – Andrew Duncan Jun 01 '16 at 00:00
  • @Oren see http://stackoverflow.com/questions/24869481/detect-if-app-is-being-built-for-device-or-simulator-in-swift – Airsource Ltd May 19 '17 at 11:58
  • 1
    @Dimitris It's good practice. You don't know how TARGET_OS_SIMULATOR has been defined, so !(TARGET_OS_SIMULATOR) may not be identical to !TARGET_OS_SIMULATOR – Airsource Ltd May 19 '17 at 12:00
  • There is a better way to do this now. See my answer in this thread https://stackoverflow.com/a/49236898/2272561 – Stefan Vasiljevic Sep 20 '18 at 15:02
106

Updated code:

This is purported to work officially.

#if TARGET_IPHONE_SIMULATOR
NSString *hello = @"Hello, iPhone simulator!";
#elif TARGET_OS_IPHONE
NSString *hello = @"Hello, device!";
#else
NSString *hello = @"Hello, unknown target!";
#endif

Original post (since deprecated)

This code will tell you if you are running in a simulator.

#ifdef __i386__
NSLog(@"Running in the simulator");
#else
NSLog(@"Running on a device");
#endif
Community
  • 1
  • 1
Pete
  • 3,991
  • 3
  • 31
  • 30
61

Not pre-processor directive, but this was what I was looking for when i came to this question;

NSString *model = [[UIDevice currentDevice] model];
if ([model isEqualToString:@"iPhone Simulator"]) {
    //device is simulator
}
gerry3
  • 21,420
  • 9
  • 66
  • 74
Daniel Magnusson
  • 9,541
  • 2
  • 38
  • 43
60

There is a better way now in Swift.

As of Xcode 9.3 and newer, you can use #if targetEnvironment(simulator) to check.

#if targetEnvironment(simulator)
//Your simulator code
#endif
Cœur
  • 37,241
  • 25
  • 195
  • 267
Stefan Vasiljevic
  • 4,315
  • 1
  • 18
  • 17
55

The best way to do this is:

#if TARGET_IPHONE_SIMULATOR

and not

#ifdef TARGET_IPHONE_SIMULATOR

since its always defined: 0 or 1

Taranfx
  • 10,361
  • 17
  • 77
  • 95
45

In case of Swift we can implement following

We can create struct which allows you to create a structured data

struct Platform {
    static var isSimulator: Bool {
        #if targetEnvironment(simulator)
            // We're on the simulator
            return true
        #else
            // We're on a device
             return false
        #endif
    }
}

Then If we wanted to Detect if app is being built for device or simulator in Swift then .

if Platform.isSimulator {
    // Do one thing
} else {
    // Do the other
}
Nischal Hada
  • 3,230
  • 3
  • 27
  • 57
  • Cleanest implementation in my opinion, and it accounts for x86_64 and i386 architectures. Helped me overcome a weird device vs. simulator bug in Core Data. You're the man! – Iron John Bonney May 26 '16 at 22:01
  • 5
    In Playground, you will get a warning, "Code after 'return' will never be executed". So I think `#if #else #endif` will be better. – DawnSong Nov 10 '17 at 08:40
32

Works for Swift 4.1 and newer and Xcode 9.3 and newer

Use this code:

#if targetEnvironment(simulator)
   // Simulator
#else
   // Device
#endif
Cœur
  • 37,241
  • 25
  • 195
  • 267
Haroldo Gondim
  • 7,725
  • 9
  • 43
  • 62
  • This basically repeats [the solution](https://stackoverflow.com/a/49236898) provided 4 months earlier. – Cristik Oct 23 '22 at 05:52
9

All those answer are good, but it somehow confuses newbie like me as it does not clarify compile check and runtime check. Preprocessor are before compile time, but we should make it clearer

This blog article shows How to detect the iPhone simulator? clearly

Runtime

First of all, let’s shortly discuss. UIDevice provides you already information about the device

[[UIDevice currentDevice] model]

will return you “iPhone Simulator” or “iPhone” according to where the app is running.

Compile time

However what you want is to use compile time defines. Why? Because you compile your app strictly to be run either inside the Simulator or on the device. Apple makes a define called TARGET_IPHONE_SIMULATOR. So let’s look at the code :

#if TARGET_IPHONE_SIMULATOR

NSLog(@"Running in Simulator - no app store or giro");

#endif
onmyway133
  • 45,645
  • 31
  • 257
  • 263
8

For Swift 4.2 / Xcode 10

I created an extension on UIDevice, so I can easily ask for if the simulator is running.

// UIDevice+CheckSimulator.swift

import UIKit

extension UIDevice {
    
    /// Checks if the current device that runs the app is xCode's simulator
    static func isSimulator() -> Bool {        
        #if targetEnvironment(simulator)
            return true
        #else
            return false
        #endif
    }
}

In my AppDelegate for example I use this method to decide wether registering for remote notification is necessary, which is not possible for the simulator.

// CHECK FOR REAL DEVICE / OR SIMULATOR
if UIDevice.isSimulator() == false {
        
    // REGISTER FOR SILENT REMOTE NOTIFICATION
    application.registerForRemoteNotifications()
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
LukeSideWalker
  • 7,399
  • 2
  • 37
  • 45
6

The previous answers are a little dated. I found that all you need to do is query the TARGET_IPHONE_SIMULATOR macro (no need to include any other header files [assuming you are coding for iOS]).

I attempted TARGET_OS_IPHONE but it returned the same value (1) when running on an actual device and simulator, that's why I recommend using TARGET_IPHONE_SIMULATOR instead.

Stunner
  • 12,025
  • 12
  • 86
  • 145
  • TARGET_OS_IPHONE is for code that might run on iOS or on MacOS X. Obviously you would want that code to behave the "iPhone" way on a simulator. – gnasher729 Apr 05 '16 at 08:41
6

In swift :

#if (arch(i386) || arch(x86_64))
...            
#endif

From Detect if app is being built for device or simulator in Swift

Community
  • 1
  • 1
CedricSoubrie
  • 6,657
  • 2
  • 39
  • 44
  • To distinguish between mac apps: #if ( arch( i386 ) || arch( x86_64 ) ) && !os( OSX ) // we’re on a simulator running on mac, and not a mac app. (For cross platforms code included in mac targets) – Bobjt Oct 21 '16 at 21:01
5

Has anyone considered the answer provided here?

I suppose the objective-c equivalent would be

+ (BOOL)isSimulator {
    NSOperatingSystemVersion ios9 = {9, 0, 0};
    NSProcessInfo *processInfo = [NSProcessInfo processInfo];
    if ([processInfo isOperatingSystemAtLeastVersion:ios9]) {
        NSDictionary<NSString *, NSString *> *environment = [processInfo environment];
        NSString *simulator = [environment objectForKey:@"SIMULATOR_DEVICE_NAME"];
        return simulator != nil;
    } else {
        UIDevice *currentDevice = [UIDevice currentDevice];
        return ([currentDevice.model rangeOfString:@"Simulator"].location != NSNotFound);
    }
}
Vijay Sharma
  • 2,252
  • 1
  • 17
  • 21
4

I had the same problem, both TARGET_IPHONE_SIMULATOR and TARGET_OS_IPHONE are always defined, and are set to 1. Pete's solution works, of course, but if you ever happen to build on something other than intel (unlikely, but who knows), here's something that's safe as long as the iphone hardware doesn't change (so your code will always work for the iphones currently out there):

#if defined __arm__ || defined __thumb__
#undef TARGET_IPHONE_SIMULATOR
#define TARGET_OS_IPHONE
#else
#define TARGET_IPHONE_SIMULATOR 1
#undef TARGET_OS_IPHONE
#endif

Put that somewhere convenient, and then pretend that the TARGET_* constants were defined correctly.

1

To include all types of "simulators"

NSString *model = [[UIDevice currentDevice] model];
if([model rangeOfString:@"Simulator" options:NSCaseInsensitiveSearch].location !=NSNotFound)
{
    // we are running in a simulator
}
jeffr
  • 27
  • 1
  • 4
    It has nothing to do with Xcode 7. If you run iOS Simulator with iOS8 (from Xcode 7) then this will work. It won't work for iOS9 where [[UIDevice currentDevice] model] returns only "iPhone" if app was launched from iOS Simulator – nsinvocation Sep 23 '15 at 08:46
  • why not `-[NSString containsString]`? – Gobe Oct 31 '16 at 23:23
1

With Swift 4.2 (Xcode 10), we can do this

#if targetEnvironment(simulator)
  //simulator code
#else 
  #warning("Not compiling for simulator")
#endif
SmileBot
  • 19,393
  • 7
  • 65
  • 62
iHS
  • 5,372
  • 4
  • 31
  • 49
1

if nothing worked, try this

public struct Platform {

    public static var isSimulator: Bool {
        return TARGET_OS_SIMULATOR != 0 // Use this line in Xcode 7 or newer
    }

}
Aklesh Rathaur
  • 1,837
  • 18
  • 19
0

My answer is based on @Daniel Magnusson answer and comments of @Nuthatch and @n.Drake. and I write it to save some time for swift users working on iOS9 and onwards.

This is what worked for me:

if UIDevice.currentDevice().name.hasSuffix("Simulator"){
    //Code executing on Simulator
} else{
    //Code executing on Device
}
euthimis87
  • 1,134
  • 1
  • 11
  • 18
  • 1
    The code won't work if a user adds `Simulator` word in his device name – mbelsky May 09 '16 at 08:11
  • Unfortunately with XCode 8 ```UIDevice.current.name``` reports the name of the machine the Simulator is running on (typically something like "Simon's MacBook Pro" now) so the test has become unreliable. I am still looking into a clean way to fix it. – Michael Sep 26 '16 at 11:04
0

/// Returns true if its simulator and not a device

public static var isSimulator: Bool {
    #if (arch(i386) || arch(x86_64)) && os(iOS)
        return true
    #else
        return false
    #endif
}
Pratyush Pratik
  • 683
  • 7
  • 14
0

Apple has added support for checking the app is targeted for the simulator with the following:

#if targetEnvironment(simulator)
let DEVICE_IS_SIMULATOR = true
#else
let DEVICE_IS_SIMULATOR = false
#endif
David Corbin
  • 524
  • 2
  • 11
  • 25
-4

This worked for me best

NSString *name = [[UIDevice currentDevice] name];


if ([name isEqualToString:@"iPhone Simulator"]) {

}
Mani
  • 340
  • 2
  • 6
-5

In my opinion, the answer (presented above and repeated below):

NSString *model = [[UIDevice currentDevice] model];
if ([model isEqualToString:@"iPhone Simulator"]) {
    //device is simulator
}

is the best answer because it is obviously executed at RUNTIME versus being a COMPILE DIRECTIVE.

Eric
  • 3,301
  • 4
  • 33
  • 39
user1686700
  • 758
  • 1
  • 5
  • 5
  • 11
    I disagree. This code ends up in your product, whereas a compiler directive keeps the - on the device unnecessary - routine out. – nine stones Oct 24 '13 at 03:16
  • 1
    The compiler directives work because the device and simulators are completely different compile targets - ie you wouldn't use the same binary on both. It *has* to be compiled to different hardware, so it makes sense in that case. – Brad Parks Mar 12 '14 at 22:52
  • Being executed at RUNTIME makes it the _worst_ possible answer. – gnasher729 Apr 05 '16 at 08:43