Почему objective-c не имеет проверки доступности API?

Swift 2 имеет API проверку доступности.

Компилятор даст вам ошибку при использовании API, слишком нового для вашего минимальная целевая ОС

Почему компилятор objective-c не может использовать эквивалент?

Я тестировал проверку доступности API в googled, и были получены только быстрые результаты 2, поэтому я предполагаю, что компилятор для объективного c не может этого сделать.

Ответ 1

Предупреждение (Swift делает ошибку) просто не было реализовано в компиляторе Clang уже много лет, но это не присущее ограничение Objective-C (хотя из-за его динамического характера вы не сможете поймать все случаи), или терминология Свифт.

Макросы Apple (например, NS_CLASS_AVAILABLE) и исходные атрибуты (__attribute__((visibility(...))), __attribute__((availability(...)))) для аннотирования заголовков с информацией о доступности были в течение многих лет, и они широко используются в Apple SDK. Макросы определяются в Foundation NSObjCRuntime.h и заголовках системы Availability.h/AvailabilityMacros.h, и компилятор может (и делает) читать их.

В начале 2015 года добавлено предупреждение -Wpartial-availability в ветвь Clang master, но это предупреждение/фиксация не было сделано его путь в версию Apple Clang до (включая) Xcode 7.2. Вы получите журнал unknown warning option при добавлении флага предупреждения в проект в Xcode 7.2, но флаг доступен в Xcode 7.3. В настоящее время для него нет предопределенных настроек, но вы можете добавить флаг в Other Warning Flags в разделе "Настройки сборки".

Существуют и другие инструменты, которые используют библиотеки LLVM для обнаружения частично доступных API, например Deploymate. Для моей дипломной работы я разработал инструмент, который интегрируется непосредственно в Xcode и основан на модификации компилятора Clang. Код по-прежнему онлайн, но я не справился с общей разработкой Clang, поэтому он не будет очень полезен, кроме обучения цели. Однако "официальный" код (связанный выше) намного чище и лучше.

Изменить: Начиная с Xcode 9, проверка доступности будет работать и для Objective-C (и C). Вместо использования вышеупомянутого предупредительного флага, который не поддерживает временное/локальное развертывание цели развертывания и, следовательно, вызывает множество ложных срабатываний, там -Wunguarded-availability и if (@available(iOS 11, *)) {...} для проверки и повышения цели развертывания для следующего блока код. По умолчанию он отключен, но -Wunguarded-availability-new будет включен по умолчанию и начнет проверять что-либо за пределами iOS/tvOS 11, watchOS 4 и High Sierra. Более подробную информацию об этом можно найти в Xcode 9 бета-версиях, которая в настоящее время требует входа в систему с учетной записью разработчика.

Ответ 2

Xcode 9.0 выводит синтаксис проверки доступности во время выполнения от Swift до Objective-C:

if (@available(macOS 10.9, *))
{
// call 10.9+ API
}
else
{
// fallback code
}

в комплекте с предупреждениями для вызова API, которые новее, чем ваш целевой объект развертывания (если эти вызовы не завернуты в проверки).

finally;)

Ответ 3

Объект C не имеет проверки доступности как часть языка, так как тот же результат доступен через препроцессор Objective C. Это "традиционный" способ сделать это на языках C.

Хотите узнать, скомпилированы ли в режиме отладки?

#ifdef DEBUG
  // code which will be inserted only if compiled in debug mode
#endif 

Хотите проверить во время компиляции для минимальной версии? Используйте заголовок Availability.h в iOS и аналогичные заголовки для Mac OS X.

Этот файл находится в каталоге /usr/include.

просто проверьте __IPHONE_OS_VERSION_MAX_ALLOWED с препроцессором, например:

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
            if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
                [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert) categories:nil]];
            }else{
                [[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert)];
            }
#else
            [[UIApplication sharedApplication] registerUserNotificationSettings: (UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert)];
#endif

Поскольку у Swift нет препроцессора, им приходилось изобретать способ делать такие проверки внутри самого языка.

Если вы хотите проверить доступность метода во время выполнения, обратите внимание, что подходящим способом является метод отвечаетSoSelector: или экземплярыRespondToSelector: (последний на класс).

Обычно вы хотите комбинировать оба подхода, компилировать условную компиляцию и проверку времени выполнения.

Проверка наличия метода Objective C, например. на уровне класса:

if ([UIImagePickerController instancesRespondToSelector:
              @selector (availableCaptureModesForCameraDevice:)]) {
    // Method is available for use.
    // Your code can check if video capture is available and,
    // if it is, offer that option.
} else {
    // Method is not available.
    // Alternate code to use only still image capture.
}

Если вы хотите проверить, существует ли функция C во время выполнения, это еще проще: если она существует, сама функция не равна нулю.

Вы не можете использовать одинаковый подход на обоих языках.

Ответ 4

Конечно, вы получите ошибки в коде Objective-C. Но вы не найдете результатов в google для Objective-C, если вы используете термин, определенный для Swift, поскольку вы не найдете сайт kisuaheli в google, если вы ищете немецкое слово.; -)

Вы получите сообщение об ошибке, связывающее код Objective-C со слишком старым SDK. Это просто потому, что используемый метод или класс или $все не определены в заголовке для этого SDK. Опять же, конечно.

Это типичный быстрый маркетинг Apple: из-за неспособности Swift им нужно расширить язык, чтобы получить что-то, что довольно легко в Objective-C. Вместо того, чтобы пояснить, что это результат плохой работы Свифта, они говорят вам, что это отличная особенность Свифта. Это как вырезать пальцы, а затем сказать: "У нас отличная штукатурка!!!!!!!!" И вам нужно подождать только несколько дней, и один приходит на SO с Q: "Почему Objective-C не обладает великолепной штукатуркой?" Простой ответ: он не режет пальцы.

Проблема заключается не в том, чтобы генерировать ошибки. Проблема состоит в том, чтобы иметь один исходный код для всех версий, поэтому вы можете просто изменить версию SDK и получить новый код (или ошибки). Это необходимо для упрощения обслуживания.

В Objective-C вы просто можете использовать ответ, найденный здесь: Условно скрыть код из компилятора или вы можете сделать это во время выполнения, как указано в комментариях к Q. (Но это другое решение проблемы по своей природе, потому что это динамический подход вместо статического, как вам нужно делать в Swift.)

Причина наличия языковой функции в Swift заключается в том, что у Swift нет препроцессора, поэтому решение Objective-C не работает в Swift. Поэтому условный код был бы невозможен в Swift, и им пришлось добавить функцию штукатурки, а также язык.