Совместимость 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.

Другие вопросы по тегам