Совместимость Swift и Objc - доступность не работает только в objc - PullRequest
0 голосов
/ 15 января 2019

Хотя здесь 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()

возвращает ошибку:

«Читатель» доступен только на 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. Любая помощь, пожалуйста?

1 Ответ

0 голосов
/ 15 января 2019

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

...