Совместимость Swift и Objc - доступность не работает только в objc

Хотя здесь Apple заявляет, что следует применять флаг Swift available также в objc, у меня это не работает. Что я делаю не так?


У меня есть следующие объявления в файлах Swift:

@objc protocol Readable: AnyObject {...}

@available(iOS 10.3, *)
@objc class Reader: NSObject, Readable {...}

Итак, давайте проверим, выдает ли он ошибку, когда я пытаюсь инициализировать его в проекте до ios-10 без проверки версии. Если я напишу следующий код в Swift:

let tmp = 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.


Я попытался отметить класс с помощью:

  • @доступно(iOS 11, *)
  • @доступно(iOS, введено: 10.3)

Ни один из этих способов не работает (выдает ошибку) в objc. Любая помощь, пожалуйста?


person Nat    schedule 15.01.2019    source источник


Ответы (1)


Объект Objective-C имеет __attribute__((availability)) дольше, чем @available. Чтобы это работало, компилятор Objective-C слабо связывает символы, недоступные в целевом объекте развертывания. Это означает, что компиляция всегда завершается успешно, и запуск вашего приложения завершается успешно, но во время выполнения символ будет иметь значение NULL, если он недоступен.

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

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

Старый способ проверить, найден ли символ во время выполнения, — это просто сравнить его с 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 в Swift. Однако, чтобы сохранить обратную совместимость, возможно, никогда не возникнет ошибка времени компиляции (на уровнях ошибок по умолчанию) попытка использовать символ, который может быть недоступен в целевом объекте развертывания в Objective-C.

person zneak    schedule 15.01.2019
comment
Разве это не должно по крайней мере выдавать предупреждение ..? Потому что для меня это не в objc. - person Nat; 16.01.2019
comment
@Vive, проверьте, включает ли вызов вашего компилятора флаг предупреждения -Wunguarded-availability или -Wunguarded-availability-new. Вы должны быть в состоянии найти параметр, который управляет им, в настройках сборки вашего проекта, раздел Apple Clang — Предупреждения — все языки, как Незащищенная доступность. - person zneak; 16.01.2019
comment
Флаг -Wungarded-availability-new будет предупреждать только о незащищенных API, представленных в macOS ›= 10.13, iOS ›= 11, watchOS. ›= 4 и tvOS ›= 11 (чтобы избежать рассылки предупреждений о старом коде). - person zneak; 16.01.2019
comment
Я уже проверил это.. и я был неправ! У меня unguarded availability установлено на YES, а должно быть YES (all versions). Проблемы исправлены, спасибо! - person Nat; 16.01.2019
comment
@Vive Вы имеете в виду, что с настройкой YES (all versions) у вас теперь возникает ошибка сборки в коде Objective-C при создании экземпляра Reader ниже iOS 10.3? - person Niko; 03.11.2020
comment
@Niko Вы знаете, что последняя активность в этой теме была почти 2 года назад? Swift действительно многое изменил, совместимость objc-swift и компилятор, поэтому, если вам это нужно, вы можете протестировать его. Из приведенного выше разговора я понимаю, что отображалась ошибка. У вас есть проблемы с реализацией этого решения? Если да, задайте прямой вопрос. - person Nat; 04.11.2020
comment
@Vive, спасибо, что уделили время ответу, я видел, что это было 2 года назад, но сделал ошибку, не используя прошедшее время в моем вопросе, извините за это. Я знаю, что все движется быстро, но некоторые нет, поэтому я хотел знать, каков был конечный результат. - person Niko; 04.11.2020