Swift provides a special preprocessor directive called os
to check what operating system you are running:
struct A {
#if os(iOS)
let a: AvailableOnIOS
#elseif os(tvOS)
let a: AvailableOnTVOS
#endif
}
I am interested if there is something similar in Objective-C that can be used like
@interface A: NSObject
#if os(iOS)
@property (nonatomic, strong) AvailableOnIOS* a;
#elseif os(tvOS)
@property (nonatomic, strong) AvailableOnTVOS* a;
#endif
@end
The answer to your question is:
@interface A : NSObject
#if TARGET_OS_IOS
@property(nonatomic) AvailableOnIOS * a;
#elsif TARGET_OS_TV
@property(nonatomic) AvailableOnTVOS * a;
#endif
@end
Do not use TARGET_OS_IPHONE
as that includes all embedded systems. Just as TARGET_OS_MAC
includes all Apple systems.
To quote from Apple's TargetConditionals.h
header:
+--------------------------------------------------------------------------------------+
| TARGET_OS_MAC |
| +-----+ +------------------------------------------------------------+ +-----------+ |
| | | | TARGET_OS_IPHONE | | | |
| | | | +-----------------+ +----+ +-------+ +--------+ +--------+ | | | |
| | | | | IOS | | | | | | | | | | | | |
| | OSX | | | +-------------+ | | TV | | WATCH | | BRIDGE | | VISION | | | DRIVERKIT | |
| | | | | | MACCATALYST | | | | | | | | | | | | | |
| | | | | +-------------+ | | | | | | | | | | | | |
| | | | +-----------------+ +----+ +-------+ +--------+ +--------+ | | | |
| +-----+ +------------------------------------------------------------+ +-----------+ |
+--------------------------------------------------------------------------------------+
The reason why MAC covers everything is because all the other operating systems are in fact stripped down macOS systems, so MAC has become a synonym for "Apple Platform". The other platforms on this level are:
TARGET_OS_WIN32
TARGET_OS_WINDOWS
TARGET_OS_UNIX
TARGET_OS_LINUX
TARGET_OS_MAC
And iPhone OS (today named iOS) was the first stripped down version of macOS, all other systems are modified version of iPhone OS, that's why the layer below TARGET_OS_MAC
is split into:
TARGET_OS_OSX
TARGET_OS_IPHONE
TARGET_OS_SIMULATOR
TARGET_OS_DRIVERKIT
And TARGET_OS_IPHONE
has the following sublayers:
TARGET_OS_IOS
TARGET_OS_TV
TARGET_OS_WATCH
TARGET_OS_VISION
TARGET_OS_BRIDGE
There is one final sublayer below TARGET_OS_IOS
and that is TARGET_OS_MACCATALYST
. "Mac Catalyst" is not truly a platform of its own but instead it is a subset of the iOS API extended with desktop API functionality. This added desktop functionality is how iPadOS differs from iOS on iPhones: They are both iOS but iPadOS has additional functionality that standard iOS on iPhone has not. The entire Catalyst API was backported to macOS, so apps that are limited to the Catalyst API can run on iPads and on Macs without further modification. Note that most normal iPhone apps can also run on Macs but only on ARM Macs, whereas Catalyst apps can also run on Intel Macs, as the Catalyst APIs are also available for x86_64 systems.
Missing in this picture is TARGET_OS_SIMULATOR
which is always set when code runs in a simulator; no matter what simulator. E.g. if you want a piece of code to only be used when you run in an iOS simulator but not in other simulators (tvOS, watchOS), then you would use
#if TARGET_OS_SIMULATOR && TARGET_OS_IOS
#endif
Note that this code will not run on a real iOS device either.
Also noteworthy are the defines for different target CPUs:
TARGET_CPU_PPC
TARGET_CPU_PPC64
TARGET_CPU_68K
TARGET_CPU_X86
TARGET_CPU_X86_64
TARGET_CPU_ARM
TARGET_CPU_ARM64
TARGET_CPU_MIPS
TARGET_CPU_SPARC
TARGET_CPU_ALPHA
and the defines for the following properties:
TARGET_RT_LITTLE_ENDIAN
: Generated code uses little endian format for integersTARGET_RT_BIG_ENDIAN
: Generated code uses big endian format for integersTARGET_RT_64_BIT
: Generated code uses 64-bit pointersTARGET_RT_MAC_MACHO
: TARGET_OS_MAC
is true and Mach-O/dlyd runtime is usedAll other target conditionals are deprecated or pretty much useless in practice.