Сохранение NSUserActivity обратно совместимым с Xcode 9 - PullRequest
0 голосов
/ 31 августа 2018

Используя Xcode 10 (бета 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?

Ответы [ 2 ]

0 голосов
/ 03 сентября 2018

Условие доступности (если #available), которое вы используете, как вы правильно заметили, оценивается во время выполнения, но компилятор будет использовать эту информацию для обеспечения безопасности во время компиляции (он предупредит вас, если вы вызываете API не существует минимальной цели развертывания).

Для условно компилируемого кода вы должны использовать Блок условной компиляции

#if compilation condition
statements
#endif

Чтобы условно построить ваш код на основе версии XCode, вы можете включить в параметры сборки условие Active Compilation (флаг быстрой компоновки -D), чтобы его имя динамически создавалось на основе версии XCode. Затем используйте это как условие компиляции. Xcode уже предоставляет настройку сборки XCODE_VERSION_MAJOR, которая разрешает текущую версию Xcode (например, 0900 для Xcode 9). Таким образом, вы можете добавить условие активной компиляции с именем XCODE_VERSION _ $ (XCODE_VERSION_MAJOR), которое будет преобразовано в флаг XCODE_VERSION_0900 для Xcode 9.

enter image description here

Затем вы можете условно скомпилировать ваш код, используя:

#if XCODE_VERSION_0900
statements
#endif

У меня есть пример проекта здесь

0 голосов
/ 01 сентября 2018

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

(Этот ответ предполагает, что вы используете Swift 4.2 на Xcode 10.)

...