哪些条件编译用来在Mac和iPhone之间切换特定的代码?

我正在开发一个包含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,它仍然会使用新的常量,这似乎是不正确的。

提前感谢任何帮助!

你在观察中犯了错误。 🙂

在构buildMac或iPhone应用程序时, TARGET_OS_MAC将为1。 你是对的,这样的事情是没用的。

但是,构buildMac应用程序时, TARGET_OS_IPHONE为0。 为了这个目的,我TARGET_OS_IPHONE在头上使用TARGET_OS_IPHONE

喜欢这个:

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

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

“正确的做法是使用新的常量,因为如果你看看头文件,你会看到它们在枚举中被声明为旧的,这意味着即使在旧的版本(新常量编译到相同的东西,因为枚举被编译到应用程序,他们不能改变而不打破二进制兼容性)唯一的原因不这样做是如果你需要继续build设更旧的SDK(这是一个不同于支持较旧版本,您可以在针对较新的SDK进行编译时执行此操作)。

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

  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 

请注意,如果你真的在做这个比较,你会想把[[UIDevice currentDevice] systemVersion] compare:@"4.0"]的结果[[UIDevice currentDevice] systemVersion] compare:@"4.0"] 。 您通常也想使用弱连接等function来显式testingfunction,而不是进行版本比较,但这不是枚举的选项。

要使用的macros在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 

要使用的macros集包括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代码。