斯威夫特#available关键字vs responsesToSelector [英] Swift #available keyword vs respondsToSelector
问题描述
According to the pre-release Swift 2 documentation there is now an #available
keyword that can be used with an if let
or guard
statement for checking API availability. It gives the following example:
let locationManager = CLLocationManager()
if #available(iOS 8.0, OSX 10.10, *) {
locationManager.requestWhenInUseAuthorization()
}
或
let locationManager = CLLocationManager()
guard #available(iOS 8.0, OSX 10.10, *) else { return }
locationManager.requestWhenInUseAuthorization()
(文档)所声明的内容等同于以下Objective-C代码:
Which it (the doc) states is the equivalent of the following Objective-C code:
if ([CLLocationManager instancesRespondToSelector:@selector(requestWhenInUseAuthorization)]) {
// Method is available for use.
} else {
// Method is not available.
}
很明显,respondsToSelector:
仅适用于NSObject
的子类,而#available
关键字甚至适用于纯" Swift代码,因此,我很欣赏这一优势.
Obviously respondsToSelector:
only works on subclasses of NSObject
whereas the #available
keyword will work even for "pure" Swift code, so I appreciate that advantage.
但是,自从开始iOS开发以来,我一直被认为这种情况的最佳实践是检测API的存在,而不是依赖于其引入的版本.
However since starting iOS development I've always been led to believe that the best practice for this situation is to detect the presence of an API rather than rely on the version it was introduced.
作为一个更具体的示例,我在想苹果公司何时在iOS 7中的NSArray
上引入了firstObject
,但追溯地使其回到了iOS 4(可以使用但私有).任何使用respondsToSelector:
的代码都可以在iOS<上运行. 7,但显然版本检查将失败.
As a more concrete example I'm thinking of when Apple introduced firstObject
on NSArray
in iOS 7 but retroactively made it available back to iOS 4 (where it was available, but private). Any code using respondsToSelector:
would have worked on iOS < 7 but obviously a version check would fail.
转移到我错过的#available
关键字是否有任何好处?
Are there any benefits to shifting to the #available
keyword that I've missed?
推荐答案
一个很大的优点是Xcode 7中的Swift 2编译器比较了 类,方法,属性等的可用性对部署不利 项目的目标.
A big advantage is that the Swift 2 compiler in Xcode 7 compares the availability of classes, methods, properties, ... against the deployment target of your project.
使用respondsToSelector
总是容易出错.对于Objective-C,
Using respondsToSelector
was always error-prone. For Objective-C,
if ([CLLocationManager instancesRespondToSelector:@selector(requestWhenInUseAuthorization)]) {
编译器仅验证requestWhenInUseAuthorization
是否为
已知方法,但无法验证该检查在逻辑上是否正确.
the compiler only verifies if requestWhenInUseAuthorization
is some
known method, but it cannot verify if that check is logically correct.
在Swift中,情况更糟,因为只能将选择器指定为 字符串,并且编译器不验证任何内容.
In Swift it is even worse because selectors can only be specified as strings and the compiler does not verify anything.
使用Swift 2/Xcode 7,对应的代码
With Swift 2/Xcode 7, the corresponding code
let locationManager = CLLocationManager()
if locationManager.respondsToSelector("requestWhenInUseAuthorization") {
locationManager.requestWhenInUseAuthorization()
}
如果部署目标小于iOS 8,
将不再编译 错误消息是
does not compile anymore if the deployment target is less than iOS 8, the error message is
error: 'requestWhenInUseAuthorization()' is only available on iOS 8.0 or newer
locationManager.requestWhenInUseAuthorization()
^
note: add 'if #available' version check
使用
let locationManager = CLLocationManager()
if #available(iOS 8.0, OSX 10.10, *) {
locationManager.requestWhenInUseAuthorization()
}
编译器知道该方法仅在iOS 8及更高版本上被调用 并没有抱怨.
the compiler knows that the method will only be called on iOS 8 and later and does not complain.
这篇关于斯威夫特#available关键字vs responsesToSelector的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!