【问题标题】:Return dynamic generic Type返回动态泛型类型
【发布时间】:2018-03-26 19:23:55
【问题描述】:

已在 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,因为我的打印语句是这样说的。

当我删除调用 getType() 并直接放置 B.self 时,我得到完全相同的打印值。而且比我没有遇到运行时错误。

这两种方式有什么区别?为什么我直接输入 B.self 的方式 2 有效,而我的第一种方式却没有,尽管 print 语句中的值表明方式 1 和方式 2 的值是相同的。

【问题讨论】:

  • 这是一个已知错误 (bugs.swift.org/browse/SR-5928),已在 Swift 4.1 中修复 - 在 Swift 4.1 中,解码器将解码 B
  • @Hamish YES :) 谢谢你告诉我!!

标签: swift generics


【解决方案1】:

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 仅支持一个层次结构级别。

【讨论】:

  • 有什么办法让它动态化吗?
  • @J.Doe 我不认为你可以用Codable 让它动态化。但是你真的需要让它动态吗?
  • 嗯,我得到了很多符合可解码超类的对象。如果方法可以是动态的,这样就省去了我那么多行重复的代码,就为了改变对象的类型。
  • @J.Doe 我用可能的解决方案更新了我的答案。不过不太好
  • 是的哈哈,这也是我的备份解决方案。嗯,我正在尝试另一种方法,但我找不到任何方法:(
猜你喜欢
  • 2013-08-04
  • 2019-01-03
  • 1970-01-01
  • 1970-01-01
  • 2011-02-02
  • 2021-06-02
  • 2016-12-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多