Слабая связь - проверьте, существует ли класс и использует ли этот класс

Я пытаюсь создать универсальное приложение для iPhone, но оно использует класс, определенный только в более новой версии SDK. Структура существует для более старых систем, но класс, определенный в структуре, не работает.

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

Ответ 1

TL;DR

Ток:

  • Swift: if #available(iOS 9, *)
  • Obj-C, iOS: if (@available(iOS 11.0, *)
  • Obj-C, OS X: if (NSClassFromString(@"UIAlertController"))

Legacy:

  • Swift (версии до 2.0): if objc_getClass("UIAlertController")
  • Obj-C, iOS (версии до 4.2): if (NSClassFromString(@"UIAlertController"))
  • Obj-C, iOS (версии до 11.0): if ([UIAlertController class])

Swift 2 +

Хотя исторически было рекомендовано проверять возможности (или существование класса), а не конкретные версии ОС, это не очень хорошо работает в Swift 2.0 из-за введения проверка доступности.

Используйте этот способ вместо этого:

if #available(iOS 9, *) {
    // You can use UIStackView here with no errors
    let stackView = UIStackView(...)
} else {
    // Attempting to use UIStackView here will cause a compiler error
    let tableView = UITableView(...)
}

Примечание. Если вы попытаетесь использовать objc_getClass(), вы получите следующую ошибку:

⛔️ 'UIAlertController' доступен только на iOS 8.0 или новее.


Предыдущие версии Swift

if objc_getClass("UIAlertController") != nil {
    let alert = UIAlertController(...)
} else {
    let alert = UIAlertView(...)
}

Обратите внимание, что objc_getClass() более надежна, чем NSClassFromString() или objc_lookUpClass().


Objective-C, iOS 4.2 +

if ([SomeClass class]) {
    // class exists
    SomeClass *instance = [[SomeClass alloc] init];
} else {
    // class doesn't exist
}

Подробнее см. code007.


OS X или предыдущие версии iOS

Class klass = NSClassFromString(@"SomeClass");
if (klass) {
    // class exists
    id instance = [[klass alloc] init];
} else {
    // class doesn't exist
}

Используйте NSClassFromString(). Если он возвращает nil, класс не существует, в противном случае он вернет объект класса, который можно использовать.

Это рекомендуемый способ в соответствии с Apple в этот документ:

[...] Ваш код будет проверять существование класса [a] с использованием NSClassFromString(), который вернется действительный объект класса, если класс [] существует или нет, если это не так. Если класс существует, ваш код может его использовать [...]

Ответ 2

Для новых проектов, использующих базовый SDK iOS 4.2 или новее, есть новый рекомендуемый подход, который должен использовать метод класса NSObject для проверки доступности слабо связанных классов во время выполнения. то есть.

if ([UIPrintInteractionController class]) {
    // Create an instance of the class and use it.
} else {
    // Alternate code path to follow when the
    // class is not available.
}

источник: https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/cross_development/Using/using.html#//apple_ref/doc/uid/20002000-SW3

Этот механизм использует макрос NS_CLASS_AVAILABLE, который доступен для самой структуры в iOS (обратите внимание, что может быть какая-то инфраструктура, которая еще не поддерживает NS_CLASS_AVAILABLE - проверьте примечание о выпуске iOS для этого). Также может потребоваться конфигурация дополнительных настроек, которая может быть прочитана в приведенной выше ссылке документации Apple, однако преимущество этого метода заключается в том, что вы получаете проверку статического типа.