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

psy*_*tik 87 backwards-compatibility weak-linking ios

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

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

Sen*_*ful 162

TLDR

当前:

  • 斯威夫特:if #available(iOS 9, *)
  • Obj-C,iOS:if (@available(iOS 11.0, *))
  • Obj-C,OS X:if (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+

虽然历史上建议检查功能(或类存在)而不是特定的OS版本,但由于可用性检查的引入,这在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(...)
}
Run Code Online (Sandbox Code Playgroud)

注意:如果您尝试使用objc_getClass(),则会收到以下错误:

⛔️'UIAlertController'仅适用于iOS 8.0或更高版本.


以前版本的Swift

if objc_getClass("UIAlertController") != nil {
    let alert = UIAlertController(...)
} else {
    let alert = UIAlertView(...)
}
Run Code Online (Sandbox Code Playgroud)

请注意,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
}
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请参阅code007的答案.


OS X或以前版本的iOS

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

使用NSClassFromString().如果它返回nil,则该类不存在,否则它将返回可以使用的类对象.

这是Apple在本文档中推荐的方式:

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

  • 值得注意的是,这是OSX上的_only_方式,但不是iOS(4.2+)上的"最佳"方式,尽管它可行.请参阅code007的iOS特定答案. (2认同)

cod*_*007 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.
}
Run Code Online (Sandbox Code Playgroud)

来源: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文档链接中阅读,但是,此方法的优点是您可以进行静态类型检查.

  • 游戏有点晚了,但我在尝试构建包含`UIAlertController`的代码同时仍然支持iOS 7时遇到了这个问题.code007的答案是正确的,但需要的额外配置是弱链接(设置为`Required` to!Optional`)你的项目中的UIKit(至少在这种情况下). (3认同)