Swift:iOS 部署目标命令行标志

Posted

技术标签:

【中文标题】Swift:iOS 部署目标命令行标志【英文标题】:Swift: iOS Deployment Target Command Line Flag 【发布时间】:2014-08-13 16:34:55 【问题描述】:

如何在 Swift 条件编译语句中检查 ios 部署目标?

我尝试了以下方法:

#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
    // some code here
#else
    // other code here
#endif

但是,第一个表达式导致编译错误:

Expected '&&' or '||' expression

【问题讨论】:

***.com/questions/24003291/… @VincentGuerci 谢谢。我看到了,但它没有回答我的(更具体的)问题。 您需要的一切都在此链接中,尤其是在苹果文档中,我认为没有内置的 __IPHONE_OS_VERSION_MIN_REQUIRED 或类似的可用(还没有?),但您可以使用自己的构建配置变量。或者可能使用通过 .h 标头导入到 swift 中的“简单宏”来欺骗。 @VincentGuerci 是的,__IPHONE_OS_VERSION_MIN_REQUIRED 是内置的。如果您在 Xcode 中将它输入到您的 .swift 文件之一并单击它,Xcode 会将您带到它的声明:var __IPHONE_OS_VERSION_MIN_REQUIRED: CInt get 。我不想指定多余的命令行标志。我想使用内置的,这样当我将 Xcode 中的 iOS 部署目标更改为 iOS 8(及更高版本)时,Xcode 可以正确编译我的代码。 我刚看到your answer。谢谢,详尽的解释。我现在只注释掉我的 iOS 8 代码。然后,一旦 Apple 公开发布 iOS 8,我将停止支持 iOS 【参考方案1】:

TL;博士? > 转到 3。解决方案

1。 Swift 中的预处理

根据Apple documentation on preprocessing directives:

Swift 编译器不包含预处理器。相反,它需要 编译时属性、构建配置和 语言特性来完成相同的功能。为了这 原因是 Swift 中没有导入预处理器指令。

这就是为什么您在尝试使用 __IPHONE_OS_VERSION_MIN_REQUIRED &lt; __IPHONE_8_0(这是一个 C 预处理指令)时出错的原因。使用 swift 您不能将#if&lt; 等运算符一起使用。你所能做的就是:

#if [build configuration]

或带条件:

#if [build configuration] && ![build configuration]

2。条件编译

再次来自the same documentation:

构建配置包括文字 true 和 false 值, 命令行标志,以及在 下表。您可以使用 -D 指定命令行标志。

truefalse:帮不了我们 平台测试功能os(iOS)arch(arm64) > 对您没有帮助,搜索了一下,无法确定它们的定义位置。 (可能在编译器本身?) 命令行标志:开始吧,这是您可以使用的唯一选项...

3。解决方案

感觉有点像一种解决方法,但确实有效:

现在例如,您可以使用#if iOSVersionMinRequired7 而不是__IPHONE_OS_VERSION_MIN_REQUIRED &gt;= __IPHONE_7_0,当然假设您的目标是iOS7。

这与在项目中更改 iOS 部署目标版本基本相同,只是不太方便... 当然,您可以根据您的 iOS 版本目标使用相关方案进行多重构建配置。

Apple 肯定会改进这一点,可能会使用一些内置功能,例如 os()...

【讨论】:

现在有函数os()arch()。 developer.apple.com/library/prerelease/ios/documentation/Swift/…【参考方案2】:

在 Swift 2.2 中测试

Deployment Target 是指iOS version,还是App Target?如果您有多个版本的应用程序(免费应用程序、付费应用程序......),下面我将提供解决方案,以便您使用不同的应用程序目标。

您可以设置自定义构建配置: 1. 转到您的项目/选择您的目标/构建设置/搜索自定义标志 2. 对于您选择的目标,使用 -D 前缀(不带空格)设置自定义标志,用于调试和发布 3. 为您拥有的每个目标执行上述步骤

要区分目标,您可以执行以下操作:

var target: String 
    var _target = ""
    #if BANANA
        _target = "Banana"
    #elseif MELONA
        _target = "Melona"
    #else
        _target = "Kiwi"
    #endif
    return _target


override func viewDidLoad() 
    super.viewDidLoad()
    print("Hello, this is target: \(target)"

【讨论】:

我奇怪的好奇心。显然,这很有效,而且非常棒。谢谢!但是“-D”前缀有什么作用呢?它有什么用? @TheoBendixson 是告诉编译器后面的内容应该被视为自定义标志。例如,如果您想设置一个以“Og”开头的标志,无论出于何种原因,这都会被误解为试图同时传递“-O”和“-g”标志。 它也能在 Release 中工作吗? (D 不只是用于调试吗?) @RoiMulia True,D 与“调试”无关。它也适用于发布。【参考方案3】:

你不能在这样的条件编译语句中做到这一点。 Swift 不支持 Apple 所称的“复杂宏”。在他们看来,泛型和类型做同样的事情,结果更好。 (这是他们发布的链接https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html#//apple_ref/doc/uid/TP40014216-CH8-XID_13)

这是我想出的一个函数,它完成了同样的事情(显然只需将字符串返回替换为对您有用的任何内容,例如布尔值或只是选项本身):

func checkVersion(ref : String) -> String 
    let sys = UIDevice.currentDevice().systemVersion
    switch sys.compare(ref, options: NSStringCompareOptions.NumericSearch, range: nil, locale: nil) 
    case .OrderedAscending:
        return ("\(ref) is greater than \(sys)")
    case .OrderedDescending:
        return ("\(ref) is less than \(sys)")
    case .OrderedSame:
        return ("\(ref) is the same as \(sys)")
    


// Usage
checkVersion("7.0") // Gives "7.0 is less than 8.0"
checkVersion("8.0") // Gives "8.0 is the same as 8.0"
checkVersion("8.2.5") // Gives "8.2.5 is greater than 8.0"

【讨论】:

谢谢,但这是一个 runtime 解决方案。我正在寻找一个 compile-time 解决方案。我现在只注释掉我的 iOS 8 代码。然后,一旦 Apple 公开发布 iOS 8,我将停止支持 iOS @MattDiPasquale 如果您有一个令人信服的编译时解决方案用例,您应该向 Apple 提交增强请求。你会帮助每个人的! @matt 我不记得为什么我想要一个编译时解决方案。也许我没有充分的理由,但基于my comment above,我想我在 iOS 8 仍处于测试阶段并希望能够更改 iOS 部署目标时为 iOS 8 编写代码已经超越了自己(在 Xcode 中指定)从 8 点到 7 点,然后将我的应用程序归档到 App Store。而且我想我不想创建一个新分支或让我的应用在不同版本的 iOS 上以不同的方式运行。【参考方案4】:

我知道你的问题在这里已经有一段时间了,但万一有人还在寻找答案,他们应该知道从 Swift 2.0 开始你可以这样做:

if #available(iOS 8, *) 
    // iOS 8+ code
 else 
    // older iOS code

您可以阅读更多关于它的信息here。

【讨论】:

这在运行时检查,但我的问题是如何在编译时检查。 我很确定,当您在“旧”括号中标记为从 iOS 8 开始可用的代码(如我给出的示例中)时,您无法编译它? 所以也许我'我并没有通过编译时间与运行时得到你的意思,但我想说这不是运行时检查? 没关系 :) 再想一想我明白你的意思 :P 太晚了 :) 长话短说:两个分支都必须编译和类型检查。 但是,我想这引发了一个问题:为什么你需要一个显式的编译时检查,而这很可能会奏效? ? 好问题。我试着在this comment回答。【参考方案5】:

我最近在构建一个库时遇到了这个问题,该库的源代码支持具有不同功能的多个 iOS 和 macOS 版本。

我的解决方案是在 Xcode 中使用自定义构建标志,这些标志从实际部署目标中派生出它们的值:

TARGET_IOS_MAJOR = TARGET_IOS_MAJOR_$(IPHONEOS_DEPLOYMENT_TARGET:base)
TARGET_MACOS_MAJOR = TARGET_MACOS_MAJOR_$(MACOSX_DEPLOYMENT_TARGET:base)

参考 Others Swift Flags 中的那些用户定义设置,例如:

OTHER_SWIFT_FLAGS = -D$(TARGET_MACOS_MAJOR) -D$(TARGET_IOS_MAJOR)

允许我在我的 Swift 源代码中检查实际的主要操作系统版本,如下所示:

#if os(macOS)
    #if TARGET_MACOS_MAJOR_12
        #warning("TARGET_MACOS_MAJOR_12")

    #elseif TARGET_MACOS_MAJOR_11
        // use custom implementation
        #warning("TARGET_MACOS_MAJOR_11")
    #endif

#elseif os(iOS)
    #if TARGET_IOS_MAJOR_15
        #warning("TARGET_IOS_MAJOR_15")

    #elseif TARGET_IOS_MAJOR_14
        #warning("TARGET_IOS_MAJOR_14")

    #else
        #warning("older iOS")
    #endif
#endif

目前我不知道在 SPM 包中是否可以使用类似的方法。这是我将在稍后阶段尝试做的事情。

【讨论】:

以上是关于Swift:iOS 部署目标命令行标志的主要内容,如果未能解决你的问题,请参考以下文章

来自命令行的 xcodebuild:文件的编译标志

AppEngine文档建议使用命令行标志而不是app.yaml文件元素

Appium 服务命令行参数

用 Swift 编写的工程代码静态分析命令行工具 smck

仅使用cordova的命令行创建IOS应用程序

在 C/C++ 中处理命令行标志