Swift: флаг целевой строки для развертывания iOS

Как проверить цель развертывания iOS в операторе условной компиляции Swift?

Я пробовал следующее:

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

Но первое выражение вызывает ошибку компиляции:

Expected '&&' or '||' expression

5 ответов

TL; DR? > Перейти к 3. Решение

1. Предварительная обработка в Swift

Согласно документации Apple по директивам предварительной обработки:

Компилятор Swift не включает препроцессор. Вместо этого он использует преимущества атрибутов времени компиляции, конфигураций сборки и языковых функций для достижения той же функциональности. По этой причине директивы препроцессора не импортируются в Swift.

Вот почему у вас есть ошибка при попытке использовать __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0 которая является директивой предварительной обработки C С быстрым вы просто не можете использовать #if с такими операторами, как <, Все, что вы можете сделать, это:

#if [build configuration]

или с условиями:

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

2. Условная компиляция

Опять из той же документации:

Конфигурации сборки включают буквальные значения true и false, флаги командной строки и функции тестирования платформы, перечисленные в таблице ниже. Вы можете указать флаги командной строки, используя -D <# flag #>.

  • true а также false: Не поможет нам
  • Функции тестирования платформы: os(iOS) или же arch(arm64) > Не поможет, немного искал, не могу понять, где они определены. (в самом компиляторе может быть?)
  • флаги командной строки: здесь мы идем, это единственный вариант, который вы можете использовать...

3. Решение

Походит на обходной путь, но делает работу: Другие флаги Swift

Теперь, например, вы можете использовать #if iOSVersionMinRequired7 вместо __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0 Предполагая, конечно, что ваша цель - iOS7.

По сути, это то же самое, что и изменение целевой версии развертывания iOS в вашем проекте, просто менее удобно... Конечно, вы можете использовать конфигурации Multiple Build со связанными схемами в зависимости от ваших целевых версий iOS.

Apple, безусловно, улучшит это, возможно, с помощью некоторой встроенной функции, такой как os()...

Протестировано в 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)"
}

Недавно я столкнулся с этой проблемой при создании библиотеки, исходный код которой поддерживает несколько версий iOS и macOS с разной функциональностью.

Мое решение использует пользовательские флаги сборки в Xcode, которые получают свое значение из фактической цели развертывания:

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

Ссылаясь на эти пользовательские настройки в других флагах Swift , например:

      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 2.0 вы можете сделать что-то вроде этого:

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

Вы можете прочитать больше об этом здесь.

Вы не можете сделать это в условии условной компиляции. "Сложные макросы", как их называет Apple, не поддерживаются в Swift. Дженерики и типы делают то же самое, с их точки зрения, с лучшими результатами. (Вот ссылка, которую они опубликовали https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html)

Вот функция, которую я придумал, которая выполняет то же самое (и, очевидно, просто заменяет возвращаемые строки тем, что вам полезно, например, логическим значением или просто самой опцией):

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"
Другие вопросы по тегам