17

我有一个同时具有 iOS 和 OS X 目标的项目。当我为 OS X 编译时,是否有一个正确的预处理器宏?我试过这个:

#if TARGET_OS_MAC
@interface BFNode : NSObject <NSPasteboardReading, NSPasteboardWriting> {
#else
@interface BFNode : NSObject {
#endif

TARGET_OS_MAC似乎不起作用。当我尝试在 iOS 上运行该应用程序时,出现编译器错误,因为它尝试编译第一行并且NSPasteboardReadingiOS 上没有定义协议。

我知道也有TARGET_OS_IPHONE。如果我使用它并交换它的@interface声明,它就可以工作。

但是有很多地方我有代码,没有 iOS 版本,所以我也需要 OS X 的宏。

解决方案:

我最终在 .pch 文件中定义了一个新宏:

#define TARGET_OSX TARGET_OS_IPHONE == 0
4

7 回答 7

43

根据TargetConditionals.h(似乎,截至 2020 年;任何平台)中的文档:

+---------------------------------------------------------------------+
|                            TARGET_OS_MAC                            |
| +---+ +-----------------------------------------------+ +---------+ |
| |   | |               TARGET_OS_IPHONE                | |         | |
| |   | | +---------------+ +----+ +-------+ +--------+ | |         | |
| |   | | |      IOS      | |    | |       | |        | | |         | |
| |OSX| | |+-------------+| | TV | | WATCH | | BRIDGE | | |DRIVERKIT| |
| |   | | || MACCATALYST || |    | |       | |        | | |         | |
| |   | | |+-------------+| |    | |       | |        | | |         | |
| |   | | +---------------+ +----+ +-------+ +--------+ | |         | |
| +---+ +-----------------------------------------------+ +---------+ |
+---------------------------------------------------------------------+

这告诉我们:

  • TARGET_OS_MAC1适用于(可能)在 Apple 平台上运行的任何 Cocoa 应用程序。

    • TARGET_OS_OSX1适用于 macOS 目标
    • TARGET_OS_IPHONE适用于1任何非 Mac Apple 产品
      • TARGET_OS_IOS仅适用于 iOS
        • TARGET_OS_MACCATALYST仅适用于Project Catalyst。它似乎TARGET_OS_UIKITFORMAC也将起作用。
      • TARGET_OS_TV仅适用于 tvOS
      • TARGET_OS_WATCH仅适用于 watchOS
      • TARGET_OS_BRIDGE仅适用于bridgeOS(目前甚至不支持 3rd-party 应用程序,因此您可能总是会看到0
    • TARGET_OS_DRIVERKIT1在为DriverKit构建时

⚠️但是等等!⚠️

我是从 iOS 14(macOS 11、watchOS 7)SDK 中得到的。如果我回顾 iOS 13(macOS 10.15,watchOS 6)SDK,我会看到:

+----------------------------------------------------------------+
|                TARGET_OS_MAC                                   |
| +---+  +-----------------------------------------------------+ |
| |   |  |          TARGET_OS_IPHONE                           | |
| |OSX|  | +-----+ +----+ +-------+ +--------+ +-------------+ | |
| |   |  | | IOS | | TV | | WATCH | | BRIDGE | | MACCATALYST | | |
| |   |  | +-----+ +----+ +-------+ +--------+ +-------------+ | |
| +---+  +-----------------------------------------------------+ |
+----------------------------------------------------------------+

值得注意的是,TARGET_OS_DRIVERKIT它是 14 年的新产品,现在TARGET_OS_MACCATALYST在里面IOS。这告诉我,针对 iOS 14 SDK 进行编译可能会破坏为 iOS 13 编写的一些 C 代码,如果它假设TARGET_OS_MACCATALYST并且IOS完全独立的话。


此外,还定义了这些:

  • TARGET_OS_SIMULATOR仅适用于iOS、tvOS 和 watchOS 模拟器。您可以使用上述#defines进一步细化它
  • TARGET_OS_WIN32以防您想使用 Apple 的 SDK 来制作 Windows 应用程序。除了 Apple 自己的(如 iTunes、Safari 和 QuickTime),我个人不知道其他任何东西。如果您想随身携带现有的 Objective-C 代码,现在 Swift 支持 Windows,这可能会变得有用。
  • TARGET_OS_UNIX适用于非 Apple UNIX 系统

这些已被弃用,不应再使用。也就是说,您可能会在必须维护的代码中找到它们,因此它们的含义如下:

  • TARGET_IPHONE_SIMULATOR以前是指iPhoneOS模拟器
  • TARGET_OS_EMBEDDED用于表示 iOS、tvOS 和 watchOS 非模拟设备
  • TARGET_OS_NANO可能曾经是指 iPod Nano(我在网上找不到任何历史用法)

还有一点需要注意的是,TargetConditionals.hswift-corelibs-foundation中使用的是显着不同的,包括#define用于 Android、Cygwin 和其他未明确支持但技术上可以工作的平台的 s。

我不完全确定该怎么做。我猜这是为了编译 Swift Foundation 框架,而不是为了使用它,因为 Swift 不使用#defines。

于 2018-03-29T16:12:56.227 回答
13

如果您使用的是 Swift,那么这里有一个很棒的语言功能。如果您使用的是 Objective-C,执行以下操作通常很有用:

#include <TargetConditionals.h>

#if TARGET_OS_IPHONE
    @import UIKit;
#else
    @import AppKit;
#endif

理解TARGET_OS_*定义将使这更有意义。最值得注意的是,TARGET_OS_MAC任何苹果平台都非常出乎意料。!TARGET_OS_IPHONE是 macOS,TARGET_OS_IPHONE除此之外还有什么。iOS、tvOS 和 watchOS 有更具体的定义。

来自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
于 2016-06-17T22:27:32.470 回答
8

那是因为TARGET_OS_MAC在为 iOS 构建时也定义了。

请参阅http://sealiesoftware.com/blog/archive/2010/8/16/TargetConditionalsh.html

我会尝试通过目标上的构建设置来构建我自己的目标特定定义。

于 2012-08-26T19:01:29.707 回答
4

从 Xcode 8 GM 开始,这是iOS 10.0中TargetConditionals.h的相关部分:

#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 */

(在 Xcode 文本编辑器上方的“面包屑”中,iOS 10.0 > usr/include > TargetConditionals.h

...对于 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 */ 

(在 Xcode 文本编辑器上方的“面包屑”中,macOS 10.12 > usr/include > TargetConditionals.h

TARGET_OS_MAC在两个平台上都定义为1 但仅在 macOS上定义为1 。TARGET_OS_OSX

在文件的注释中,它们描述如下:

  • TARGET_OS_MAC:生成的代码将在 Mac OS X 变体下运行。
  • TARGET_OS_OSX:生成的代码将在 OS X 设备下运行。

我想在那时的某个时候(也许是在 iPhone 发布的时候?)有人认为 iOS(né “iPhone OS”)符合“Mac OS X 变体”的定义。

于 2016-09-12T03:11:24.137 回答
3

在 TargetConditionals.h 中查找整个列表,包括:

#define TARGET_OS_MAC               1
#define TARGET_OS_IPHONE            1 
#define TARGET_IPHONE_SIMULATOR     1 
于 2012-08-26T19:01:17.710 回答
0

我建议使用这个:

#define TARGET_OS_OSX (!(TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH))
于 2016-01-21T09:26:27.337 回答
0

我遇到了同样的情况,但 Swift 需要它。

Apple 开发者论坛上的这个答案对于处理NSPasteboard您遇到的协议非常有帮助,但对于 Swift。

https://forums.developer.apple.com/thread/16757

我最终做了:

#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 {

...

}

那样TFPasteboardReading和分别TFPasteboardWriting定义了 macOS 的意义NSPasteboardReadingNSPasteboardWriting在 iOS 中它没有意义,但仍然可以在 iOS 中被引用。所以代码对两者都正确编译。

于 2019-12-23T08:44:42.120 回答