更新:见下面的摘要
我正在努力将程序从Swift 1.1转换为1.2。作为其中的一部分,我遇到了这个(不完美的)代码:
func encode2(n:String, v:AnyObject)->String {
var result:String = ""
let n2 = n.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
let v2 = v.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
result = n2! + "=" + v2!
return result
}
在其他问题中,如果使用参数encode2
调用v
除String
以外的任何类型,则此程序会在运行时(不出所料)使用unrecognised selector
消息崩溃。 Swift编译器可以通过让我检查它是一个字符串来避免这种崩溃,例如:
if let v = v as? String {
let v2 = v.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
...
}
鉴于Swift 1.2对于让我使用as!
进行向下转换非常挑剔,我有点惊讶它没有让我在运行时进行类型检查AnyObject
,或者至少警告我我没有这样做。
是否存在编译器忽略此要求的一些基本原因,
或 Apple还没有解决它吗?
更新在此处和Apple论坛回答后。
该策略似乎有点奇怪,但与Swift文档一致。如果将变量定义为AnyObject
,则编译器会假定您知道它是危险的。如果计算的变量结果为AnyObject
,编译器会发出警告:
但是,如果你在AnyObject
上调用一个方法,编译器总是假设你知道你在做什么,什么都不说。
“使用Swift与Cocoa和Objective C”一书明确建议在方法名称之后编写?
,
if let v2 = v.stringByAddingPercentEscapesUsingEncoding?(NSUTF8StringEncoding) {
// ...
}
如果方法不存在,将结果变为缺少可选项而不是崩溃。但是编译器没有强制执行它。
这对我来说似乎非常不合适,但暂时还是如此。
答案 0 :(得分:1)
因为AnyObject
的目的是什么。
引自id Compatibility(在答案中引用rintaro之后的部分):
您还可以调用任何Objective-C方法并访问任何属性 无需转换为更具体的类类型。这包括 使用@objc属性标记的Objective-C兼容方法。
但是,因为输入AnyObject的对象的特定类型是 直到运行时才知道,有可能无意中写不安全 码。与Objective-C一样,如果您调用方法或访问属性,则 在AnyObject类型对象上不存在,它是一个运行时 错误。例如,以下代码无需投诉即可编译 然后在运行时导致无法识别的选择器错误:
答案 1 :(得分:0)
AnyObject
是来自the document的Swift版id
:
Swift包含一个名为
AnyObject
的协议类型,它代表任何类型的对象,就像{-1}}在Objective-C中所做的那样。id
协议允许您编写类型安全的Swift代码,同时保持无类型对象的灵活性。由于AnyObject
协议提供了额外的安全性,Swift将AnyObject
导入id
。
如果你想:
您可以利用Swift中的选项来消除代码中的常见Objective-C错误。当您在
AnyObject
类型对象上调用Objective-C方法时,方法调用实际上就像一个隐式展开的可选项。 您可以使用与协议中的可选方法相同的可选链接语法来选择性地在AnyObject上调用方法。
在您的情况下,您可以:
AnyObject
但我也想知道为什么它不是if let v2 = v.stringByAddingPercentEscapesUsingEncoding?(NSUTF8StringEncoding) {
// ... ^
}
,而是Optional
。
在Cocoa API Reference中,在API参数中,我们经常会看到ImplicitlyUnwrappedOptional
,Error!
,AnyObject!
等等......至于Objective-C互操作,似乎是默认为"隐式解包选项" ,as documented:
在某些情况下,您可能绝对确定Objective-C方法或属性永远不会返回
String!
对象引用。为了使这个特殊场景中的对象更方便使用,Swift将对象类型导入为隐式解包的选项。
也就是说,"方便" 。