Совместимость Swift и Objc - доступность не работает только в objc
Хотя здесь Apple утверждает, что Swift available
Флаг должен быть применен также в objc, он не работает для меня. Что я делаю неправильно?
У меня есть следующие объявления в файлах Swift:
@objc protocol Readable: AnyObject {...}
@available(iOS 10.3, *)
@objc class Reader: NSObject, Readable {...}
Итак, давайте проверим, выдает ли это ошибку, когда я пытаюсь инициализировать ее в проекте pre-ios-10 без проверки версии. Если я напишу следующий код в Swift:
let tmp = Reader()
возвращает ошибку:
"Reader" доступен только на iOS 10.3 или новее
Что ожидается
Однако, если я напишу следующий код в objc:
// if (@available(iOS 10.3, *)) { // commeted out to test if it succeeds without version check
Reader *tmp = [[Reader alloc] init];
// }
Сборка завершена без каких-либо ошибок, хотя я ожидаю такую же ошибку, как и в Swift.
Я пытался пометить класс с помощью:
- @available (iOS 11, *)
- @available (iOS, введено: 10.3)
Ни одна из этих работ (выдает ошибку) в objc. Любая помощь, пожалуйста?
1 ответ
Objective-C имел __attribute__((availability))
дольше чем было @available
, Чтобы заставить это работать, компилятор Objective C слабо связывает символы, которые не доступны в цели развертывания. Это означает, что компиляция всегда завершается успешно, и запуск вашего приложения завершается успешно, но символ будет НЕДЕЙСТВИТЕЛЕН во время выполнения, если он недоступен.
В зависимости от того, что это такое, вы получите более или менее изящную деградацию при попытке использовать его:
- вызов слабой связанной функции, которая отсутствует, может привести к сбою
- чтение или запись в глобальную переменную, которая отсутствует, может привести к сбою
- использование класса, который отсутствует, будет невозможным, и все методы будут возвращать ноль
Старый способ проверки того, найден ли символ во время выполнения, состоит в том, чтобы просто сравнить его с NULL:
NS_AVAILABLE_MAC(...) @interface Foo @end
int bar NS_AVAILABLE_MAC(...);
int baz(int frob) NS_AVAILABLE_MAC(...);
if ([Foo class]) { /* Foo is available */ }
if (&bar) { /* bar is available */ }
if (&baz) { /* baz is available */ }
В твоем случае:
Reader *tmp = [[Reader alloc] init];
tmp
будет nil
потому что это было бы так же, как [[nil alloc] init]
,
@available
Директива была добавлена относительно недавно в Objective-C. Теперь можно использовать @available
в Objective-C так же, как вы используете #available
в Свифте. Однако, чтобы сохранить обратную совместимость, возможно, никогда не будет ошибкой времени компиляции (при уровнях ошибок по умолчанию) пытаться использовать символ, который может быть недоступен для цели развертывания в Objective-C.