Как использовать атрибут # available в Swift

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

Этот пост не поможет вам принять решение о том, какую минимальную версию iOS вы должны поддерживать, но он будет полезным справочником в тех случаях, когда вам нужно использовать более новые API.

Проверка версии ОС для выполнения кода

Базовый пример сводится к проверке конкретной версии ОС для выполнения фрагмента кода. Например, если вы хотите выполнить часть кода только для iOS 15 и выше, вы должны использовать доступный атрибут следующим образом:

if #available(iOS 15, *) {
    print("This code only runs on iOS 15 and up")
} else {
    print("This code only runs on iOS 14 and lower")
}

Вы также можете использовать доступный атрибут внутри оператора защиты:

guard #available(iOS 15, *) else {
    print("Returning if iOS 14 or lower")
    return
}

print("This code only runs on iOS 15 and up")

Это отлично подходит для случаев, когда вы хотите выполнить определенный код только для определенной версии iOS.

Разница между @available и #available

При навигации по Swift API вы часто сталкиваетесь с атрибутом @available. Мы только что рассмотрели #attribute, который похож, но немного отличается. Самый короткий ответ, чтобы описать его отличие:

  • @available используется для обозначения доступности класса или метода.
  • #available используется только для выполнения фрагмента кода для определенных платформ и/или версий.

Настройка доступности для класса или метода

Мы можем продемонстрировать это, пометив класс или метод как доступный с iOS 14:

@available(iOS 14, *)
final class NewAppIntroduction {
    // ..
}

Как только вы попытаетесь создать экземпляр этого класса внутри проекта, который поддерживает версии ниже iOS 14, вы столкнетесь со следующей ошибкой:

Как видите, компилятор поможет нам исправить эту ошибку с помощью нескольких предложений. Два из них переместят проблему в другое место в вашем коде, пометив вызывающий класс как доступный, начиная с iOS 14. В этом случае нам поможет #available :

if #available(iOS 14, *) {
    let appIntroduction = NewAppIntroduction()
} else {
    // .. use the old app introduction
}

Мы могли бы сделать то же самое для методов, использующих атрибут @available:

@available(iOS 14, *)
func launchNewAppIntroduction() {
    let appIntroduction = NewAppIntroduction()
}

Возможные значения атрибута available

В приведенных выше примерах мы использовали только проверки iOS 14. Однако с available атрибутом в Swift мы можем сделать гораздо больше.

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

  • iOS
  • iOSApplicationExtension
  • macOS
  • macOSApplicationExtension
  • macCatalyst
  • macCatalystApplicationExtension
  • watchOS
  • watchOSApplicationExtension
  • tvОС
  • tvOSApplicationExtension
  • swift

Опции включают платформы, а также клавишу быстрого доступа для пометки фрагментов кода как доступных с определенной версии Swift.

Звездочка указывает на доступность объявления для всех названий платформ, перечисленных выше, если не указано иное. При необходимости вы также можете указать несколько платформ одновременно:

@available(iOS 15, macOS 12.0, *)
func launchNewAppIntroduction() {
    let appIntroduction = NewAppIntroduction()
}

Пометка метода как deprecated или obsoleted

Другое значение атрибута используется для пометки методов как deprecated или obsoleted. Методы начинаются как deprecated и в конечном итоге будут помечены как obsoleted. Представьте себе, что у вас есть приложение, в котором введение приложения больше не будет отображаться на iOS 14 и более поздних версиях. Вы можете пометить конкретный метод, если он используется из SDK, как deprecated и obsoleted следующим образом:

@available(iOS, deprecated: 12, obsoleted: 13, message: "We no longer show an app introduction on iOS 14 and up")
func launchAppIntroduction() {
    // ..
}

Когда разработчики нашего кода все еще пытаются использовать наши методы, они столкнутся со следующей ошибкой:

Нумерация версий при использовании этих значений часто сбивает с толку. В приведенном выше примере кода вы можете подумать, что этот метод deprecated в iOS 12 и obsoleted в iOS 13. Однако он читается по-другому:

  • Этот метод deprecated в версиях выше, чем X
  • Этот метод obsoleted в версиях выше X.

Сообщение используется для описания рассуждений и может быть полезно для объяснения изменений вашим разработчикам.

Пометка метода как переименованного

При разработке SDK для коллег, пользователей с открытым исходным кодом или других пользователей вы можете захотеть перевести разработчиков на более новые методы вашего кода. В этих случаях вы можете использовать переименованный атрибут:

@available(*, unavailable, renamed: "launchOnboarding")
func launchAppIntroduction() {
    // Old implementation
}

func launchOnboarding() {
    // New implementation
}

Обратите внимание, что сначала мы помечаем метод как недоступный. Переименованное значение указывает, какой метод следует использовать вместо этого.

Xcode хорошо поможет разработчикам, показав вариант исправления для нашего переименования:

Условие недоступности с использованием #unavailable

Часто задаваемый вопрос при работе с доступным атрибутом заключается в том, чтобы отменить оператор и написать код, например:

Запускайте это только в том случае, если версия iOS ниже X.

Swift 5.6 представил атрибут #unavailable в SE-290, позволяющий нам инвертировать доступную проверку следующим образом:

if #unavailable(iOS 15, *) {
    // Run iOS 14 and lower code.
}

Вы в основном читаете это как:

Новый API недоступен, если ОС ниже iOS 15.

Использование недоступного атрибута чище, чем код, который вам приходилось писать до Swift 5.6:

if #available(iOS 15, *) { } else {
    // Run iOS 14 and lower code.
}

Если вы читаете эту статью после обновления до Xcode 13.3, возможно, вы захотите проверить свои проекты на наличие фрагментов кода, подобных приведенным выше, и вместо этого перейти на использование проверки недоступности.

Использование нескольких недоступных платформ

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

if #unavailable(iOS 15, watchOS 9) {
    // Run on iOS 14, watchOS 8 and lower
}

Заключение

Мы рассмотрели все возможности использования атрибута available в Swift. Вы можете запускать код для определенной платформы и версий Swift, и теперь вы можете помечать методы как устаревшие, устаревшие или переименованные.