弱链接 - 检查类是否存在并使用该类

88

我正在尝试创建一款通用的iPhone应用程序,但是它使用了仅在新版本SDK中定义的类。该框架存在于旧系统中,但是在框架中定义的类不存在。

我知道我想要使用某种弱链接,但是我能找到的所有文档都是关于函数存在的运行时检查 - 我如何检查一个类是否存在?


这是什么类?也许还有其他解决方法。 - Marcelo Cantos
2个回答

165

简易版本

当前:

  • Swiftif #available(iOS 9, *)
  • Obj-C, iOSif (@available(iOS 11.0, *))
  • Obj-C, OS Xif (NSClassFromString(@"UIAlertController"))

传统:

  • 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,则该类不存在,否则它将返回可用的类对象。
这是苹果在此文档中推荐的方法:

[...]您的代码应使用NSClassFromString()来测试类的存在性,如果类存在,则返回有效的类对象,否则返回nil。 如果该类存在,则您的代码可以使用它[...]


谢谢。为了让其他人更好地理解,一旦您检测到类别,就可以使用NSClassFromString返回的Class实例来创建它(将其分配给id),并在该实例上调用选择器。 - psychotik
2
值得注意的是,这是在OSX上唯一的方法,但不是在iOS(4.2+)上最好的方法,尽管它可以工作。请参阅code007的答案以获取特定于iOS的信息。 - Ben Mosher
如果我的类不是真正的类,而是一个C结构体呢? - Nathan H
Swift 4.1 将带来新的检查 canImport提案 - dispatchMain

69

对于使用iOS 4.2或更高版本基本SDK的新项目,有一种新的推荐方法,即使用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文档链接中阅读,但这种方法的优点是可以获得静态类型检查。


3
虽然来晚了一些,但我刚遇到了一个问题,当尝试构建包含UIAlertController的代码时,仍要支持iOS 7。code007的答案是正确的,但额外需要进行的配置是将项目中的UIKit弱链接(从“必需”改为“可选”)(至少对于此情况如此)。 - Evan R

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接