哪个条件编译用于在Mac和iPhone之间切换特定代码?

时间:2010-07-05 17:53:53

标签: iphone xcode macos conditional-compilation

我正在开发一个包含Mac应用程序和共享代码的iPad应用程序的项目。如何使用条件编译开关从iPhone项目中排除特定于Mac的代码,反之亦然?我注意到TARGET_OS_IPHONETARGET_OS_MAC都是1,所以它们都是真的。是否有另一个我可以使用的开关只能在编译特定目标时返回true?

在大多数情况下,我通过将#include <UIKit/UIKit.h>#include <Cocoa/Cocoa.h>移动到两个项目的预编译头中来获得合作文件。我正在共享模型和一些实用程序代码,用于从RSS提要和Evernote获取数据。

特别是,[NSData dataWithContentsOfURL:options:error:]函数对选项参数iOS 3.2及更早版本和Mac OS 10.5采用不同的常量,早于iOS 4和Mac OS 10.6。我正在使用的条件是:

#if (TARGET_OS_IPHONE && (__IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_3_2)) || (TARGET_OS_MAC && (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5))

这似乎有效,但我想确保这是防弹的。我的理解是,如果Mac版本设置为10.6,但iOS版本设置为3.2,即使它正在编译iOS 3.2,它仍将使用新常量,这似乎是不正确的。

提前感谢您的帮助!

4 个答案:

答案 0 :(得分:65)

你的观察中犯了一个错误。 :)

在构建Mac或iPhone应用程序时,

TARGET_OS_MAC将为1。你是对的,对于这类事情来说,它毫无用处。

但是,构建Mac应用程序时TARGET_OS_IPHONE为0。为此,我一直在我的标题中使用TARGET_OS_IPHONE

像这样:

#if TARGET_OS_IPHONE
// iOS code
#else
// OSX code
#endif

这是一个很棒的图表: http://sealiesoftware.com/blog/archive/2010/8/16/TargetConditionalsh.html

答案 1 :(得分:8)

“正确的做法就是使用更新的常量,因为如果查看标题,你会发现它们被声明等同于enum中的旧标题,这意味着新常量甚至可以在旧版本中使用(两个常量编译成相同的东西,因为枚举被编译到应用程序中,它们无法在不破坏二进制兼容性的情况下进行更改。)不这样做的唯一原因是,如果您需要继续构建旧的SDK(即与支持旧版本不同的是,您可以在针对较新的SDK进行编译时执行此操作。)

如果你真的想根据操作系统版本使用不同的标志(因为新版本实际上添加了新功能,而不是只重命名常量)那么你可以做两件明智的事情,你的上面的宏都没有完成:

  1. 要始终使用旧标志,除非允许的最小版本大于它们引入的版本(如下所示):

    #if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000 || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060)
      NSDataReadingOptions  options = NSDataReadingMapped;
    #else
      NSDataReadingOptions  options = NSMappedRead;
    #end
    
  2. 有条件地只使用只能在新版本上构建的新值,并在代码中编译以确定支持这两个版本的构建在运行时的标志:

    #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
    
  3. 请注意,如果你真的在进行这种比较,你会想要隐藏[[UIDevice currentDevice] systemVersion] compare:@"4.0"]某处的结果。您通常还希望使用弱链接而不是进行版本比较来显式测试功能,但这不是枚举的选项。

答案 2 :(得分:7)

要使用的宏在SDK头文件TargetConditionals.h中定义。取自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

由于此处的所有内容都是“Mac OS X变种”,因此TARGET_OS_MAC在这种情况下无效。要专门为macOS编译,例如:

#if !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR && !TARGET_OS_EMBEDDED
    // macOS-only code
#endif

更新:较新的标头(Xcode 8+?)现在具有专为macOS定义的TARGET_OS_OSX。 (h / t @OldHorse),所以这应该有效:

#if TARGET_OS_OSX
 // macOS-only code
#endif

答案 3 :(得分:2)

要使用的宏集现在包括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

似乎可以正常编译macOS代码。