I have a project that has both an iOS and an OS X target. Is there a preprocessor macro that is true when I'm compiling for OS X? I tried this:
#if TARGET_OS_MAC
@interface BFNode : NSObject <NSPasteboardReading, NSPasteboardWriting> {
#else
@interface BFNode : NSObject {
#endif
But TARGET_OS_MAC
doesn't seem to work. When I try to run the app on iOS I get a compiler error, because it tries to compile the first line and there is no NSPasteboardReading
protocol defined on iOS.
I know there is TARGET_OS_IPHONE
too. If I use that and swap the @interface
declarations it works.
But there are a lot of places where I have code, that has no iOS version, so I need a macro for OS X too.
SOLUTION:
I ended up defining a new macro in the .pch file:
#define TARGET_OSX TARGET_OS_IPHONE == 0
As per the documentation in TargetConditionals.h
(it seems, as of 2020; any platform):
+---------------------------------------------------------------------+
| TARGET_OS_MAC |
| +---+ +-----------------------------------------------+ +---------+ |
| | | | TARGET_OS_IPHONE | | | |
| | | | +---------------+ +----+ +-------+ +--------+ | | | |
| | | | | IOS | | | | | | | | | | |
| |OSX| | |+-------------+| | TV | | WATCH | | BRIDGE | | |DRIVERKIT| |
| | | | || MACCATALYST || | | | | | | | | | |
| | | | |+-------------+| | | | | | | | | | |
| | | | +---------------+ +----+ +-------+ +--------+ | | | |
| +---+ +-----------------------------------------------+ +---------+ |
+---------------------------------------------------------------------+
This tells us:
TARGET_OS_MAC
will be 1
for (probably) any Cocoa application running on an Apple platform.
TARGET_OS_OSX
will only be 1
for macOS targets TARGET_OS_IPHONE
will be 1
for any non-Mac Apple products
TARGET_OS_IOS
is just for iOS
TARGET_OS_MACCATALYST
is just for Project Catalyst . It seems TARGET_OS_UIKITFORMAC
will also work.TARGET_OS_TV
is just for tvOS TARGET_OS_WATCH
is just for watchOS TARGET_OS_BRIDGE
is just for bridgeOS (which currently doesn't even support 3rd-party apps so you'll likely always see that be 0
) TARGET_OS_DRIVERKIT
will be 1
when building for DriverKitI got that from the iOS 14 (macOS 11, watchOS 7) SDK. If I look back into the iOS 13 (macOS 10.15, watchOS 6) SDK, I see this:
+----------------------------------------------------------------+
| TARGET_OS_MAC |
| +---+ +-----------------------------------------------------+ |
| | | | TARGET_OS_IPHONE | |
| |OSX| | +-----+ +----+ +-------+ +--------+ +-------------+ | |
| | | | | IOS | | TV | | WATCH | | BRIDGE | | MACCATALYST | | |
| | | | +-----+ +----+ +-------+ +--------+ +-------------+ | |
| +---+ +-----------------------------------------------------+ |
+----------------------------------------------------------------+
Notably, TARGET_OS_DRIVERKIT
is new in 14, and TARGET_OS_MACCATALYST
is inside IOS
now. This tells me that compiling against the iOS 14 SDK can break some C code written for iOS 13 , if it assumes that TARGET_OS_MACCATALYST
and IOS
are completely separate.
Additionally, these are defined:
TARGET_OS_SIMULATOR
is just for iOS, tvOS, and watchOS simulators . You can further refine this using the above #define
sTARGET_OS_WIN32
is in case you wanna use Apple's SDKs to make Windows apps. I don't personally know of any other than Apple's own (like iTunes, Safari, and QuickTime). This might become useful now that Swift has Windows support, if you want to take existing Objective-C code with you.TARGET_OS_UNIX
is for non-Apple UNIX systems And these are deprecated, and should not be used anymore. That said, you might find them in code you have to maintain, so here's what they meant:
TARGET_IPHONE_SIMULATOR
used to mean the iPhoneOS simulator TARGET_OS_EMBEDDED
used to mean iOS, tvOS, and watchOS non-simulated devices TARGET_OS_NANO
probably used to mean iPod Nano (I can't find any historical usage online) Something else to note is that the TargetConditionals.h
used in swift-corelibs-foundation is significantly different, and includes #define
s for Android, Cygwin, and other not-explicitly-supported-but-they-technically-work platforms.
I'm not entirely sure what to make of this. I would guess it's for compiling the Swift Foundation framework, and not for consuming it, since Swift doesn't consume #define
s.
If you're using Swift, there's a great language feature for this. If you're using Objective-C, it's often useful to do something like this:
#include <TargetConditionals.h>
#if TARGET_OS_IPHONE
@import UIKit;
#else
@import AppKit;
#endif
Understanding the TARGET_OS_*
defines will make this make a lot more sense. Most notably, TARGET_OS_MAC
is any Apple platform which is pretty unexpected. !TARGET_OS_IPHONE
is macOS and TARGET_OS_IPHONE
is anything besides that. There are more specific defines for iOS, tvOS, and watchOS.
From TargetConditions.h
:
TARGET_OS_*
These conditionals specify in which Operating System the generated code will
run. Indention is used to show which conditionals are evolutionary subclasses.
The MAC/WIN32/UNIX conditionals are mutually exclusive.
The IOS/TV/WATCH conditionals are mutually exclusive.
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
TARGET_IPHONE_SIMULATOR - DEPRECATED: Same as TARGET_OS_SIMULATOR
TARGET_OS_NANO - DEPRECATED: Same as TARGET_OS_WATCH
That is because TARGET_OS_MAC
is defined when building for iOS as well.
See http://sealiesoftware.com/blog/archive/2010/8/16/TargetConditionalsh.html on that.
I would try and build my own target specific define via build-settings on the target.
As of Xcode 8 GM, this is the relevant section of TargetConditionals.h in iOS 10.0:
#define TARGET_OS_MAC 1
#define TARGET_OS_WIN32 0
#define TARGET_OS_UNIX 0
#define TARGET_OS_OSX 0
#define TARGET_OS_IPHONE 1
#define TARGET_OS_IOS 1
#define TARGET_OS_WATCH 0
#define TARGET_OS_BRIDGE 0
#define TARGET_OS_TV 0
#define TARGET_OS_SIMULATOR 0
#define TARGET_OS_EMBEDDED 1
#define TARGET_IPHONE_SIMULATOR TARGET_OS_SIMULATOR /* deprecated */
#define TARGET_OS_NANO TARGET_OS_WATCH /* deprecated */
(In the 'breadcrumb' above the text editor in Xcode, iOS 10.0 > usr/include > TargetConditionals.h
)
...And this is the same file, for macOS:
#define TARGET_OS_MAC 1
#define TARGET_OS_WIN32 0
#define TARGET_OS_UNIX 0
#define TARGET_OS_OSX 1
#define TARGET_OS_IPHONE 0
#define TARGET_OS_IOS 0
#define TARGET_OS_WATCH 0
#define TARGET_OS_BRIDGE 0
#define TARGET_OS_TV 0
#define TARGET_OS_SIMULATOR 0
#define TARGET_OS_EMBEDDED 0
#define TARGET_IPHONE_SIMULATOR TARGET_OS_SIMULATOR /* deprecated */
#define TARGET_OS_NANO TARGET_OS_WATCH /* deprecated */
(In the 'breadcrumb' above the text editor in Xcode, macOS 10.12 > usr/include > TargetConditionals.h
)
TARGET_OS_MAC
is defined as 1 on both platforms, but TARGET_OS_OSX
is 1 only on macOS.
In the file's comments, they are described as follows:
- TARGET_OS_MAC: Generated code will run under Mac OS X variant.
- TARGET_OS_OSX: Generated code will run under OS X devices.
I guess at some point back then (perhaps around when the iPhone was announced?) somebody decided that iOS (né "iPhone OS") fits the definitions of "Mac OS X variant".
Look in TargetConditionals.h for an entire list, including:
#define TARGET_OS_MAC 1
#define TARGET_OS_IPHONE 1
#define TARGET_IPHONE_SIMULATOR 1
我建议使用这个:
#define TARGET_OS_OSX (!(TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH))
I ran into this same situation, but needed it for Swift.
This answer here on the Apple developer forums was very helpful in dealing with the NSPasteboard
protocols in your situation, but for Swift.
https://forums.developer.apple.com/thread/16757
I ended up doing:
#if os(iOS) || os(watchOS)
public protocol TFPasteboardReading { }
public protocol TFPasteboardWriting { }
#elseif os(macOS)
public typealias TFPasteboardReading=NSPasteboardReading
public typealias TFPasteboardWriting=NSPasteboardWriting
#endif
@objc(TFCategory)
public class TFCategory: TFBaseModel, TFPasteboardReading, TFPasteboardWriting {
...
}
That way TFPasteboardReading
and TFPasteboardWriting
is defined for macOS meaning NSPasteboardReading
and NSPasteboardWriting
respectively and in iOS it has no meaning, but can still be referenced in iOS. So the code compiles properly for both.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.