Отрицание Objective-C ключевое слово @available

Я хотел бы запустить фрагмент кода, только если версия iOS текущего устройства ниже определенной версии, как указано здесь. Примеры кода, приведенные Apple, выглядят следующим образом:

if (@available(iOS 10.0, *)) {
  // iOS 10.0 and above
} else {
  // below 10.0
}

Однако существуют сценарии, в которых вы хотите запустить код только в том случае, если текущая версия iOS находится ниже определенной версии. Я предположил, что следующий код будет работать:

if ([email protected](iOS 10.0, *)) {
  // below 10.0
}

Однако кажется, что это не работает, и я получаю следующее предупреждение от Xcode:

@available does not guard availability here; use if (@available) instead

Здесь - это фиксация LLVM, которая добавила диагностику, которую я вижу.

В эту проблему можно выделить два возможных варианта:

  • Используйте вариант if-else без добавления кода в блок if (не очень элегантный).
  • Продолжайте использовать старые подходы, такие как -[NSProcessInfo isOperatingSystemAtLeastVersion:].

Есть ли другой способ использования @available, который мне не хватает?

Ответ 1

Вы можете определить свои собственные пользовательские макросы, которые вы можете использовать в своем приложении. Пример: -

#define isIOS11() ([[UIDevice currentDevice].systemVersion doubleValue]>= 11.0 && [[UIDevice currentDevice].systemVersion doubleValue] < 12.0)

или

#define SinceIOS9_2 ([[UIDevice currentDevice].systemVersion doubleValue]>= 4.2 && [[UIDevice currentDevice].systemVersion doubleValue] < 9.2)

Используйте его, как показано ниже: -

if (isIOS11()) {
    // Do something for iOS 11 
} else {
    // Do something iOS Versions below 11.0
}

Пожалуйста, дайте мне знать, если это сработает для вас.

Ответ 2

Идея @available заключается в том, что вы хотите использовать API, который доступен только для определенных систем. Для других систем функциональность либо отсутствует в вашем приложении, либо вы предлагаете альтернативные функции. Правильный способ использовать его для случаев, когда вам не нужен какой-либо код за пределами определенной версии ОС, только ниже,

if (@available(iOS 10.0, *)) {
    // Happens automatically on on iOS 10 and beyond
} else {
    someOtherCode();
}

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

if (@available(...)) {

допускается только изменение пробелов и разрывов строк. Да, вы можете опасаться, что один не (!) Действительно ничего, кроме сложного, где бы вы тогда рисовали линию? Как насчет:

if ((todayIsTuesday() && @available(iOS 9.0, *)) 
    || (self.theWeatherIsNice && [email protected](iOS 11.0, *)) {

Таким образом, допускаются только простые утверждения, которые только заставляют компилятор разделить код на два раздела и где всегда будет работать только один раздел: один для перечисленных ОС и один для остальных. Разумеется, "остальное" можно затем разделить, else if это разрешено. Только раздел else может быть автоматически сгенерирован, если отсутствует, поэтому, когда вы пишете это:

if (@available(...)) {
    someCode();
} // There is no else

Компилятор также счастлив, так как это то же самое, что и

if (@available(...)) {
     someCode()
} else {
    // Nothing to do here
}