В этом коротком руководстве я бы хотел остановиться на новом синтаксисе Swift для проверки доступности. Если вы уже занимались разработкой для iOS или OS X, то я уверен, что вы знаете, насколько утомительно проверять, доступен ли определенный API на устройстве, на котором работает ваше приложение. В Swift 2 это стало намного меньше боли для разработчиков.
Проблема
Представьте себе следующий сценарий. Вы разрабатываете приложение для iOS, предназначенное для iOS 7 и выше. Во время прошлогодней WWDC Apple представила новый API для регистрации уведомлений.
1
|
registerUserNotificationSettings(_:)
|
Означает ли это, что вам нужно поднять цель развертывания приложения с iOS 7 на iOS 8? Вы могли бы сделать это, но это оставило бы значительную часть пользовательской базы вашего приложения в холодном состоянии, только чтобы соответствовать новой политике Apple для локальных и удаленных уведомлений. Ваши пользователи не будут вам благодарны за это.
Альтернативой является использование нового API только на устройствах с iOS 8 и выше. Это имеет больше смысла. Правильно? Реализация будет выглядеть примерно так.
1
2
3
4
5
6
7
8
9
|
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
if UIApplication.instancesRespondToSelector(«registerUserNotificationSettings:») {
let types = UIUserNotificationType.Alert |
let settings = UIUserNotificationSettings(forTypes: types, categories: nil)
application.registerUserNotificationSettings(settings)
}
return true
}
|
Это жизнеспособный вариант, но это не без риска. В этом уроке я не буду вдаваться в подробности того, что связаны с этими рисками, но я хочу подчеркнуть, что большинство разработчиков считают целесообразным использовать вышеуказанный подход. В следующем примере показан вариант этого подхода, на этот раз с использованием Objective-C.
1
2
3
|
if ([UIUserNotificationSettings class]) {
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge) categories:nil]];
}
|
Хотя оба подхода будут работать в большинстве ситуаций, есть ситуации, в которых вы столкнетесь с проблемами. Например, некоторые API начинают свою жизнь как частные API и становятся общедоступными на более позднем этапе. В этом случае вы можете столкнуться с частными API на устройствах с операционной системой, в которой эти API еще не опубликованы. И я уверен, что вы знаете, что это значит.
Решение
Благодаря работе команды Swift решение нашей проблемы в Swift 2 простое и понятное. Взгляните на следующий пример. Обратите внимание, что цель развертывания проекта установлена на iOS 7 с использованием Swift 2 и Xcode 7 .
В этом примере мы используем API, которые были представлены в iOS 8. Поскольку компилятор знает, что цель развертывания проекта установлена на iOS 7, он выдает ошибку, сообщая нам, что API, которые мы хотим использовать, доступны только в iOS 8 и выше. Он знает это, проверяя SDK на наличие информации. Если вы нажмете Command и выберите метод registerUserNotificationSettings(_:)
, вы должны увидеть что-то вроде этого.
1
2
|
@available(iOS 8.0, *)
func registerUserNotificationSettings(notificationSettings: UIUserNotificationSettings)
|
К счастью, Xcode дает нам решение для решения этой проблемы. Он предлагает использовать проверку версии, чтобы избежать вызова API исключительно для iOS 8 и выше, если наши пользователи запускают приложение на более старой версии iOS.
Обратите внимание, что эта функция была введена в Swift 2. Компилятор не выдаст ошибку, если вы используете Swift 1.2. Добавление проверки версии также облегчает понимание примера. Взгляните на обновленный пример ниже, в котором мы следуем совету, который дал нам XCode.
1
2
3
4
5
6
7
8
9
|
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
if #available(iOS 8.0, *) {
let types = UIUserNotificationType([UIUserNotificationType.Alert, UIUserNotificationType.Sound, UIUserNotificationType.Badge])
let settings = UIUserNotificationSettings(forTypes: types, categories: nil)
application.registerUserNotificationSettings(settings)
}
return true
}
|
Синтаксис ясен и понятен. Используя синтаксис доступности, мы проверяем, запущено ли приложение на устройстве с iOS 8 и выше. Если это не так, предложение if
пропускается, в противном случае приложение вызывает новый API для регистрации уведомлений.
Синтаксис
Синтаксис прост. Мы запускаем условие доступности с #available
и #available
условие в скобки. Мы можем добавить столько платформ, сколько необходимо, разделяя список платформ запятыми.
1
2
3
|
if #available(iOS 8.0, OSX 10.10, watchOS 2, *) {
…
}
|
Обратите внимание, что мы заканчиваем список платформ звездочкой. Эта звездочка обязательна и указывает на то, что условие if
выполняется для цели минимального развертывания для любой платформы, не включенной в список платформ.
Как мы видели ранее, мы можем использовать атрибут @available
для добавления информации о доступности в функции, методы и классы. В следующем примере мы сообщаем компилятору, что useFancyNewAPI
должен useFancyNewAPI
только на устройствах с iOS 9 и выше.
1
2
3
4
|
@available(iOS 9.0, *)
func useFancyNewAPI() {
…
}
|
Вывод
Имейте в виду, что синтаксис доступности не является альтернативой для двух примеров, которые я показал вам в начале этого урока. Эти примеры ошибочны и должны использоваться, только если вы используете Objective-C или более раннюю версию Swift.
Доступный синтаксис — еще одна причина для миграции ваших проектов Swift на Swift 2. Он избавляется от подверженных ошибкам решений для проверки доступности API. С Swift 2 мир выглядит немного дружелюбнее.