返回动态泛型类型

时间:2018-03-26 19:23:55

标签: swift generics

已在Swift 4.1中修复

下面描述的问题已在Swift 4.1中修复,请参阅Hamish的评论

问题

我在这段代码上遇到运行时错误:

class A: Decodable{
    let a: Int
}

class B: A{
    let b: Int = 1 // side problem 2: class B has no initializers. 
                   //Why? It conforms to Decodable right??
}

func getType() -> A.Type{
    return B.self
}

class Test: UIViewController{

    override func viewDidLoad() {
        super.viewDidLoad()
        let data = ["a": 100, "b": 200]
        let jsonData =  try! JSONSerialization.data(withJSONObject: data)
        let t =         try! JSONDecoder().decode(getType(), from: jsonData)
        print((t as! B).b) //run-time
    }
}

因为t不是B.奇怪,我返回B.self。如果我打印getType(),我会得到:MyProject.B,所以虽然在我的方法签名中我返回了A.Type,但它应该是B.type,因为我的print语句是这样说的。

当我移除呼叫getType()并直接放置B.self时,我得到完全相同的打印值。而且比我得到运行时错误。

这两种方式有什么区别?为什么我直接输入B.self的方式2,以及我的第一种方式不起作用,尽管print语句中的值表示方式1和方式2的值相同。

1 个答案:

答案 0 :(得分:0)

JSONDecoder.decode()是一个泛型函数,泛型在运行时得到解析。这意味着不使用getType()的运行时行为,编译器仅依赖于函数声明。

另外,Decodable需要一个具体类型来处理,这是在编译时选择的类型,因为它需要知道要使用哪些解码容器。

如果对类型进行静态处理,则可以获得一些动态行为:

func decode(from data: Data, type: A.Type) throws {
    let decoder = JSONDecoder()
    if type == A.self { return try decoder.decode(data, type: A.self) }
    else if type == B.self { return try decoder.decode(data, type: B.self) }
    else { throw TypeNotSupportedError }
}

基本上在某些时候你需要给解码器一个具体的类型。

关于错误#2,编译器似乎只自动生成Codable支持一个层次结构级别。