简体   繁体   English

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

[英]Which conditional compile to use to switch between Mac and iPhone specific code?

I am working on a project that includes a Mac application and an iPad application that share code. 我正在开发一个包含Mac应用程序和共享代码的iPad应用程序的项目。 How can I use conditional compile switches to exclude Mac-specific code from the iPhone project and vice-versa? 如何使用条件编译开关从iPhone项目中排除特定于Mac的代码,反之亦然? I've noticed that TARGET_OS_IPHONE and TARGET_OS_MAC are both 1, and so they are both always true. 我注意到TARGET_OS_IPHONETARGET_OS_MAC都是1,所以它们都是真的。 Is there another switch I can use that will only return true when compiling for a specific target? 是否有另一个我可以使用的开关只会在编译特定目标时返回true?

For the most part, I've gotten the files to cooperate by moving #include <UIKit/UIKit.h> and #include <Cocoa/Cocoa.h> into the precompile headers for the two projects. 在大多数情况下,我通过将#include <UIKit/UIKit.h>#include <Cocoa/Cocoa.h>到两个项目的预编译头文件中来获得合作文件。 I'm sharing models and some utility code that fetches data from RSS feeds and Evernote. 我正在共享模型和一些实用程序代码,用于从RSS提要和Evernote获取数据。

In particular, the [NSData dataWithContentsOfURL:options:error:] function takes a different constant for the options parameter iOS 3.2 and earlier and Mac OS 10.5 and earlier than it does for iOS 4 and Mac OS 10.6. 特别是, [NSData dataWithContentsOfURL:options:error:]函数对选项参数iOS 3.2及更早版本和Mac OS 10.5采用不同的常量,早于iOS 4和Mac OS 10.6。 The conditional I'm using is: 我正在使用的条件是:

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

This seems to work, but I want to make sure this is bulletproof. 这似乎有效,但我想确保这是防弹的。 My understanding is that if the Mac version is set to 10.6, but the iOS version is set to 3.2, it will still use the new constants even if it's compiling for iOS 3.2, which seems incorrect. 我的理解是,如果Mac版本设置为10.6,但iOS版本设置为3.2,即使它正在编译iOS 3.2,它仍然会使用新的常量,这似乎是不正确的。

Thanks in advance for any help! 在此先感谢您的帮助!

You've made a mistake in your observations. 你在观察中犯了一个错误。 :) :)

TARGET_OS_MAC will be 1 when building a Mac or iPhone application. 在构建Mac或iPhone应用程序时, TARGET_OS_MAC将为1。 You're right, it's quite useless for this sort of thing. 你是对的,对于这种事情来说,这是无用的。

However, TARGET_OS_IPHONE is 0 when building a Mac application. 但是,构建Mac应用程序时TARGET_OS_IPHONE为0。 I use TARGET_OS_IPHONE in my headers all the time for this purpose. TARGET_OS_IPHONE ,我TARGET_OS_IPHONE在我的标题中使用TARGET_OS_IPHONE

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 这是一个很棒的图表: http//sealiesoftware.com/blog/archive/2010/8/16/TargetConditionalsh.html

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

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

  1. 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 
  2. 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. 请注意,如果您实际上正在进行这种比较,那么您希望将[[UIDevice currentDevice] systemVersion] compare:@"4.0"]的结果存储[[UIDevice currentDevice] systemVersion] compare:@"4.0"] 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. 您通常还希望使用弱链接而不是进行版本比较来显式测试功能,但这不是枚举的选项。

The macros to use are defined in the SDK header file TargetConditionals.h . 要使用的宏在SDK头文件TargetConditionals.h中定义。 Taken from the 10.11 SDK: 取自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. 由于此处的所有内容都是“Mac OS X变体”,因此TARGET_OS_MAC在这种情况下无用。 To compile specifically for macOS, for example: 要专门为macOS编译,例如:

#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. 更新:较新的标题(Xcode 8+?)现在具有专门为macOS定义的TARGET_OS_OSX (h/t @OldHorse), so this should work: (h / t @OldHorse),所以这应该工作:

#if TARGET_OS_OSX
 // macOS-only code
#endif

The set of macros to use includes now TARGET_OS_OSX: 要使用的宏集现在包括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. 似乎适用于条件编译macOS代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM