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. Решение
Походит на обходной путь, но делает работу:
Теперь, например, вы можете использовать #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"