我正在编写一个可以从JSON解析类型ID的库。但是,我发现类型转换规则有点莫名其妙。
示例:
class AccountId : NSString { }
let json : AnyObject? = "user-1" // Returned by NSJSONSerialization.JSONObjectWithData
let s = json as? NSString // Succeeds, s == Some("user-1")
let a = json as? AccountId // Fails, a == nil
为什么第一个类型转换成功而第二个类型转换失败?有没有什么神奇的NSString
不与Swift-only类交叉?
我正在使用XCode版本6.1(6A1030)(撰写本文时的最新版本)。
答案 0 :(得分:22)
作为一般规则,如果您有A - >类的层次结构。 B - > C(C继承自B,后者继承自A),并且你有一个B的实例,你可以向上转换为A,但你不能向下转换为C.
原因是C可能会添加B中不可用的属性,因此编译器或运行时将不知道如何初始化其他数据,更不用说还必须分配它。
请注意,polymorphism允许你使用变量进行upcast和downcast - 这意味着,如果你有一个存储在A类变量中的C实例,你可以将该变量强制转换为B和C,因为它实际上包含一个实例但是如果变量包含B的实例,则可以向下转换为B,但不能向下转换为C.
在您的情况下,您应该专注于接受NSString
的构造函数,而不是向下转换,但我怀疑在NSString
的特定情况下,它无法完成(没有NSString
指定的初始值设定项接受一个字符串作为参数)。如果您能够这样做,那么您的代码将如下所示:
var json: AnyObject? = "test"
if let string = json as? NSString {
let a = AccountId(string: string)
}
此时您可以a
使用AccountId
或NSString
的实例
答案 1 :(得分:1)
NSString是否有一些神奇的东西不会与仅限Swift的类交叉?
是。 Swift的String
课程自动桥接到NSString
,反之亦然。来自the docs:
Swift自动在String类型和NSString之间架起桥梁 类。这意味着您可以在任何地方使用NSString对象 使用Swift String类型代替并获得两者的好处 types- String类型的插值和Swift设计的API和 NSString类的广泛功能。出于这个原因,你应该 几乎从不需要在您自己的代码中直接使用NSString类。 事实上,当Swift导入Objective-C API时,它取代了所有的 具有String类型的NSString类型。当您的Objective-C代码使用 Swift类,导入器替换所有的String类型 导入API中的NSString。
为什么第一个类型转换成功而第二个类型转换失败?
由于String
和NSString
之间的关系很强,编译器知道如何从一个转换为另一个。另一方面,由于您的AccountId
课程是NSString
的更专业版,因此您无法从String
投射到AccountId
。