【问题标题】:Keeping NSUserActivity backwards compatible with Xcode 9保持 NSUserActivity 向后兼容 Xcode 9
【发布时间】:2018-08-31 15:10:30
【问题描述】:

使用 Xcode 10 (beta 6) 我可以毫无问题地编写和运行以下代码:

import Intents

func test() {

    let activity = NSUserActivity(activityType: "com.activtiy.type")

    activity.title = "Hello World"
    activity.isEligibleForSearch = true
    activity.isEligibleForHandoff = false

    if #available(iOS 12.0, *) {
        activity.isEligibleForPrediction = true
        activity.suggestedInvocationPhrase = "Say something"
    }

    print(activity)
}

从 iOS 12 开始,添加了 .isEligibleForPredictions.suggestedInvocationPhrase 属性,因此 Xcode 10 可以使用 if #available 条件保持代码本身向后兼容。

但是,我想确保此代码与早期版本的 Xcode 向后兼容。在 Xcode 9 中运行时,出现以下错误:

if #available(iOS 12.0, *) {
        // ERROR: Value of type 'NSUserActivity' has no member 'isEligibleForPrediction'
        activity.isEligibleForPrediction = true

        // ERROR: Value of type 'NSUserActivity' has no member 'suggestedInvocationPhrase'
        activity.suggestedInvocationPhrase = "Say something"
    }

这似乎是因为#available宏实际上是在运行时解析的,因此包含的所有代码仍然需要编译成功。

有没有办法告诉编译器在为 iOS 11 构建或使用 Xcode 9 时忽略这两行代码?

【问题讨论】:

    标签: ios swift xcode xcode10


    【解决方案1】:

    Xcode 10 使用 Swift 4.2,而 Xcode 9 使用 Swift 4.1。所以你可以在编译时使用这些知识:

    func test() {
        let activity = NSUserActivity(activityType: "com.activtiy.type")
    
        activity.title = "Hello World"
        activity.isEligibleForSearch = true
        activity.isEligibleForHandoff = false
    
        #if swift(>=4.2) // compile-time check
        if #available(iOS 12.0, *) { // run-time check
            activity.isEligibleForPrediction = true
            activity.suggestedInvocationPhrase = "Say something"
            predictionApiAvailable = true
        }
        #endif
    
        print(activity)
    }
    

    (此答案假设您在 Xcode 10 上使用 Swift 4.2。)

    【讨论】:

    • “如果你不想使用 Swift 4.2,为什么要使用 Xcode 10” - 使用 iOS 12、macOS 10.14。
    • @rmaddy:好的..我从我的答案中删除了那部分。
    • @rmaddy 很清楚我为什么使用 Xcode 10,但您的回复似乎是我在 Swift 中能找到的最佳解决方案。似乎我能做的最好的事情就是在 Objc 中重新编写类,因为有更多可用的 C 样式宏。
    • @XmasRights:在 Objective C 中,您可以使用 __IPHONE_OS_VERSION_MAX_ALLOWED 告诉您 SDK 版本。如果你不使用 Swift 4.2,我猜你必须用 Objective C 编写代码。
    • @Michael Yep - 尝试将代码库更新到 Swift 4.2,但 300 个错误仅比使用 Objective-C 更烦人
    【解决方案2】:

    您正确使用的可用性条件(如果 #available)在运行时进行评估,但编译器将使用此信息来提供编译时安全性(如果您正在调用 API,它将向您发出警告不存在最小部署目标)。

    对于条件编译代码,您必须使用Conditional Compilation Block

    #if compilation condition
    statements
    #endif
    

    要根据 Xcode 版本有条件地构建代码,您可以在构建设置中包含一个 Active Compilation Condition(一个 -D swift 编译标志),它的名称是根据 Xcode 版本动态创建的。然后将此作为编译条件。 Xcode 已经提供了构建设置 XCODE_VERSION_MAJOR 来解析当前的 Xcode 版本(例如 Xcode 9 的 0900)。因此,您可以添加一个名为 XCODE_VERSION_$(XCODE_VERSION_MAJOR) 的 Active Compilation Condition,它将解析为 Xcode 9 的标志 XCODE_VERSION_0900。

    然后您可以使用以下方法有条件地编译您的代码:

    #if XCODE_VERSION_0900
    statements
    #endif
    

    我有一个示例项目here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-17
      • 2015-07-22
      相关资源
      最近更新 更多