Which conditional compile to use to switch between Mac and iPhone specific code?
The set of macros to use includes now TARGET_OS_OSX:
TARGET_OS_WIN32 - Generated code will run under 32-bit Windows
TARGET_OS_UNIX - Generated code will run under some Unix (not OSX)
TARGET_OS_MAC - Generated code will run under Mac OS X variant
TARGET_OS_OSX - Generated code will run under OS X devices
TARGET_OS_IPHONE - Generated code for firmware, devices, or simulator
TARGET_OS_IOS - Generated code will run under iOS
TARGET_OS_TV - Generated code will run under Apple TV OS
TARGET_OS_WATCH - Generated code will run under Apple Watch OS
TARGET_OS_BRIDGE - Generated code will run under Bridge devices
TARGET_OS_SIMULATOR - Generated code will run under a simulator
TARGET_OS_EMBEDDED - Generated code for firmware
Seems to work ok for conditional compilation of macOS code.
You've made a mistake in your observations. :)
TARGET_OS_MAC
will be 1 when building a Mac or iPhone application. You're right, it's quite useless for this sort of thing.
However, TARGET_OS_IPHONE
is 0 when building a Mac application. I use TARGET_OS_IPHONE
in my headers all the time for this purpose.
Like this:
#if TARGET_OS_IPHONE
// iOS code
#else
// OSX code
#endif
Here's a great chart on this: http://sealiesoftware.com/blog/archive/2010/8/16/TargetConditionalsh.html
The macros to use are defined in the SDK header file TargetConditionals.h
. Taken from the 10.11 SDK:
TARGET_OS_WIN32 - Generated code will run under 32-bit Windows
TARGET_OS_UNIX - Generated code will run under some Unix (not OSX)
TARGET_OS_MAC - Generated code will run under Mac OS X variant
TARGET_OS_IPHONE - Generated code for firmware, devices, or simulator
TARGET_OS_IOS - Generated code will run under iOS
TARGET_OS_TV - Generated code will run under Apple TV OS
TARGET_OS_WATCH - Generated code will run under Apple Watch OS
TARGET_OS_SIMULATOR - Generated code will run under a simulator
TARGET_OS_EMBEDDED - Generated code for firmware
Since everything is a “Mac OS X variant” here, TARGET_OS_MAC
is not useful in this case. To compile specifically for macOS, for example:
#if !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR && !TARGET_OS_EMBEDDED
// macOS-only code
#endif
Update: Newer headers (Xcode 8+?) now have TARGET_OS_OSX
defined specifically for macOS. (h/t @OldHorse), so this should work:
#if TARGET_OS_OSX
// macOS-only code
#endif
"The correct thing to do is just use the newer constants, because if you look at the header you will see they are declared equivalent to the old ones in the enum, which means the new constants will work even on the old releases (both constants compile to the same thing, and since enums are compiled into the app they can't change without breaking binary compatibility). The only reason not to do that is if you need to continue building agains the older SDKs (that is a different thing than supporting older releases, which you can do while compiling against the newer SDKs).
If you actually wanted to use different flags based on the OS version (because the new version actually added new functionality, as opposed to just renaming a constant) then there are two sensible things you can do, neither of which your above macro accomplishes:
To always use the old flags unless the min version allowed is greater than version they were introduced in (something like this):
#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000 || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060) NSDataReadingOptions options = NSDataReadingMapped; #else NSDataReadingOptions options = NSMappedRead; #end
Conditionally use only the new values in builds that can on only the new versions, and compile in code to determine the flags at runtime for builds that support both versions:
#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000 || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060) NSDataReadingOptions options = NSDataReadingMapped; #else NSDataReadingOptions options; if ([[UIDevice currentDevice] systemVersion] compare:@"4.0"] != NSOrderedAscending) { options = NSDataReadingMapped; } else { options = NSMappedRead; } #end
Note that if you actually were doing this comparison a lot you would want to stash the result of the [[UIDevice currentDevice] systemVersion] compare:@"4.0"]
somewhere. You also generally want to explicitly test for features using things like weak linking instead of doing version compares, but that is not an option for enums.