如何根据传入参数的实际类型解码JSON字符串?Swift泛型解码类型匹配问题求助
解决方案:动态获取实际类型进行解码
你的问题核心在于Swift泛型的静态类型推断:因为proxyFunction的参数类型是BaseClass,调用mainFunction(obj)时,泛型参数T会被静态推断为BaseClass,导致JSONDecoder按照BaseClass的结构解码JSON,最终得到BaseClass实例而非ExtraClass。
要解决这个问题(且不修改proxyFunction的签名),我们需要动态获取传入obj的实际类型,并基于该类型执行解码操作。同时还要修正ExtraClass的解码逻辑,确保它能正确解析surname字段。
完整修正后的代码
let data = "[{\"name\": \"Smith\", \"surname\": \"John\"}]".data(using: .utf8)! class BaseClass: Decodable { var name: String? // 定义静态解码方法,利用Self的动态特性 static func decodeArray(from data: Data) throws -> [Self] { try JSONDecoder().decode([Self].self, from: data) } } class ExtraClass: BaseClass { var surname: String? required init(from decoder: Decoder) throws { // 先解码当前类的字段 let container = try decoder.container(keyedBy: CodingKeys.self) self.surname = try container.decode(String.self, forKey: .surname) // 再调用父类的解码逻辑 try super.init(from: decoder) } init(name: String, surname: String) { super.init() self.name = name self.surname = surname } // 定义当前类的CodingKeys private enum CodingKeys: String, CodingKey { case surname } } func mainFunction(_ obj: BaseClass) { // 动态获取obj的实际类型,并调用其静态解码方法 guard let decodeArray = type(of: obj).decodeArray as? (Data) throws -> [BaseClass] else { print("无法执行动态解码") return } do { var results = try decodeArray(data) results.append(obj) // 打印验证类型和内容 results.forEach { item in if let extraItem = item as? ExtraClass { print("ExtraClass: name=\(extraItem.name ?? ""), surname=\(extraItem.surname ?? "")") } else { print("BaseClass: name=\(item.name ?? "")") } } } catch { print("解码失败: \(error)") } } func proxyFunction(_ obj: BaseClass) { mainFunction(obj) } proxyFunction(ExtraClass(name: "Sullivan", surname: "Jane"))
关键改动说明
修复
ExtraClass的解码逻辑- 原来的
init(from decoder:)只调用了父类的解码方法,没有解码surname字段,即使解码成ExtraClass实例,surname也会是nil。 - 添加了
CodingKeys枚举,并先解码当前类的字段,再调用父类的初始化方法,确保所有字段都被正确解析。
- 原来的
利用动态类型替代静态泛型推断
- 在
BaseClass中定义了静态方法decodeArray(from:),该方法的返回值[Self]会在子类中被动态替换为子类的数组类型(比如ExtraClass的decodeArray会返回[ExtraClass])。 - 在
mainFunction中,通过type(of: obj)获取obj的实际运行时类型(这里是ExtraClass.self),然后调用其decodeArray方法,这样解码出来的数组元素类型就是ExtraClass。
- 在
类型转换兼容
- 将解码得到的
[ExtraClass]转换为[BaseClass](因为ExtraClass是BaseClass的子类,这种转换是安全的),这样就能正常append传入的obj。
- 将解码得到的
运行这段代码后,你会得到两个ExtraClass实例,完全符合你的预期。
内容的提问来源于stack exchange,提问作者ov1d1u
相关产品推荐
相关产品推荐

