Swift 等同于 Objective-C 的“#ifdef __IPHONE_11_0”是什么?

What's the Swift equivalent of Objective-C's "#ifdef __IPHONE_11_0"?

我想使用 Xcode 9 将 iOS 11 代码添加到我的项目中,同时保留使用仅支持 iOS 的 Xcode 8 编译项目的选项10.

在 Objective-C 中,我可以通过使用预处理器指令来检查是否定义了 __IPHONE_11_0 来做到这一点。如果我使用早于 iOS 11 的 Base SDK 进行编译,这将隐藏代码。像这样:

#ifdef __IPHONE_11_0
    if (@available(iOS 11.0, *)) {
        self.navigationController.navigationBar.prefersLargeTitles = YES;
    }
#endif

在 Swift 中有没有办法做到这一点?

if #available(iOS 11.0, *) 不起作用,因为这是运行时检查。

iOS 11 SDK 附带 Swift 3.2(或 Swift 4),因此您可以使用 Swift 版本检查来完成同样的事情:

#if swift(>=3.2)
    if #available(iOS 11.0, *) {
        …
    }
#endif

这是Apple建议的解决方案:

if #available(iOS 11.0, *) {
    // iOS 11 specific stuff here
} else {
    // non iOS 11 stuff here
}

请参考this resource(更多详情请观看标记6:50上的视频)

我明白了。我有一个旧的 Mac 我喜欢使用它,它对 Xcode 9 来说太旧了,所以我希望有时也能够在 Xcode 8 下编译我的项目。

但是如果你只想支持 iOS 10 和 iOS 11,简单的方法是将 Xcode 目标的最低 SDK 设置为 10.0,并且始终使用 iOS 11 SDK 进行编译。 Swift 在这种情况下会为你工作,并给你语法错误,除非你正确使用 if #available(iOS 11.0, *) {

您仍然可以在 iOS 10 和 iOS 11 下进行测试,而无需为 Xcode 8 操心。

从Xcode8的角度来看,你是在试图从未来编译源代码。 Xcode 8.

没有好的解决方案

展望未来,这里是解决方案:

在Xcode9.3(Swift4.1)中,你可以说:

#if canImport(MagiciOS12Kit)
  if #available(iOS 12.0, *) {
     MagiciOS12Class.standard.method()
  }
#endif

并且您的代码仍将在 Xcode 9.3 下编译,但会跳过未来需要假设的 Xcode 10.0 或更高版本的内容。

#if canImport(moduleName) 仅在 Swift 4.1 中添加,Xcode 8 无法处理。但即便如此,这也仅适用于 Apple 未来添加的整个模块。如果 Apple 只是用新方法扩展现有的 class,就像在你的 navigationController.navigationBar.prefersLargeTitles 中一样,你仍然无法测试 prefersLargeTitles,但是你可以找到苹果与 prefersLargeTitles 同时引入的另一个框架,并使用 #if canImport(... ).

如果你想把条件放在函数之外,你可以像下面那样做。

@available(iOS 11.0, *)
func functionName() {
 // function contents
}

你可以实现,像下面这样的功能

@available(iOS 11.0, *)
func myFunction() {
 // function defination 
}

或者如果你想检查内部函数写这个

if #available(iOS 11.0, *) {
    // iOS 11 specific stuff here
} else if #available(iOS 10.0, *) {
   // iOS 10 specific stuff here
} else {
    // non iOS 11 & 10 stuff here
}