You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何根据传入参数的实际类型解码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"))

关键改动说明

  1. 修复ExtraClass的解码逻辑

    • 原来的init(from decoder:)只调用了父类的解码方法,没有解码surname字段,即使解码成ExtraClass实例,surname也会是nil。
    • 添加了CodingKeys枚举,并先解码当前类的字段,再调用父类的初始化方法,确保所有字段都被正确解析。
  2. 利用动态类型替代静态泛型推断

    • 在BaseClass中定义了静态方法decodeArray(from:),该方法的返回值[Self]会在子类中被动态替换为子类的数组类型(比如ExtraClass的decodeArray会返回[ExtraClass])。
    • 在mainFunction中,通过type(of: obj)获取obj的实际运行时类型(这里是ExtraClass.self),然后调用其decodeArray方法,这样解码出来的数组元素类型就是ExtraClass。
  3. 类型转换兼容

    • 将解码得到的[ExtraClass]转换为[BaseClass](因为ExtraClass是BaseClass的子类,这种转换是安全的),这样就能正常append传入的obj。

运行这段代码后,你会得到两个ExtraClass实例,完全符合你的预期。

内容的提问来源于stack exchange,提问作者ov1d1u

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 22:52:29