为什么Swift 1.2编译器不对AnyObject强制进行类型检查?

时间:2015-04-10 12:30:55

标签: swift types

更新:见下面的摘要

我正在努力将程序从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调用vString以外的任何类型,则此程序会在运行时(不出所料)使用unrecognised selector消息崩溃。 Swift编译器可以通过让我检查它是一个字符串来避免这种崩溃,例如:

if let v = v as? String {
    let v2 = v.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
    ...
}

鉴于Swift 1.2对于让我使用as!进行向下转换非常挑剔,我有点惊讶它没有让我在运行时进行类型检查AnyObject,或者至少警告我我没有这样做。

是否存在编译器忽略此要求的一些基本原因

Apple还没有解决它吗?

更新在此处和Apple论坛回答后。

该策略似乎有点奇怪,但与Swift文档一致。如果将变量定义为AnyObject,则编译器会假定您知道它是危险的。如果计算的变量结果为AnyObject,编译器会发出警告:

Error message

但是,如果你在AnyObject上调用一个方法,编译器总是假设你知道你在做什么,什么都不说。

“使用Swift与Cocoa和Objective C”一书明确建议在方法名称之后编写?

if let v2 = v.stringByAddingPercentEscapesUsingEncoding?(NSUTF8StringEncoding) {
     // ...
}
如果方法不存在,

将结果变为缺少可选项而不是崩溃。但是编译器没有强制执行它。

这对我来说似乎非常不合适,但暂时还是如此。

2 个答案:

答案 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参数中,我们经常会看到ImplicitlyUnwrappedOptionalError!AnyObject!等等......至于Objective-C互操作,似乎是默认为"隐式解包选项" as documented

  

在某些情况下,您可能绝对确定Objective-C方法或属性永远不会返回String!对象引用。为了使这个特殊场景中的对象更方便使用,Swift将对象类型导入为隐式解包的选项。

也就是说,"方便"