Swift-JSONDecoder-解码通用嵌套类

时间:2018-07-26 13:08:18

标签: json swift jsondecoder

我对Swift还是很陌生,我正在尝试创建一棵类树来为我的数据建模。我想使用JSONEncoder和JSONDecoder发送和接收对象。解码另一个对象(嵌套)中的通用类时遇到问题,因为在init(from:解码器)方法中,我无法访问可能对我有帮助的其他属性。

在我的代码中:

NestedSecondObject扩展了NestedObjects,从而扩展了Codable-NesteThirtObject可以扩展NestedObject,依此类推...

Contact扩展了Object1,后者扩展了Codable; 联系人包含NestedObject类型(运行时可以是NestedObject的任何子类)

因为默认情况下JSONEncoder和JSONDecoder不支持继承,所以我重写了方法“ encode”和init(来自:decoder),如此处所述:Using Decodable in Swift 4 with Inheritance

我的代码是:

class NestedSecondObject: NestedObject {
    var subfield2: Int?

    private enum CodingKeys : String, CodingKey {
        case subfield2
    }

    override init() { super.init() }

    override func encode(to encoder: Encoder) throws {
        try super.encode(to: encoder)
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(subfield2, forKey: .subfield2)
    }

    required init(from decoder: Decoder) throws
    {
        try super.init(from: decoder)
        let values = try decoder.container(keyedBy: CodingKeys.self)
        self.subfield2 = try values.decode(Int.self, forKey: .subfield2)

    }

}


class Contact:Object1 {
    var name: String = ""
    var age: Int = 0
    var address: String = ""
//    var className = "biz.ebas.platform.generic.shared.EContactModel"
    var nestedObject:NestedObject?

    private enum CodingKeys : String, CodingKey {
        case name,age,address,nestedObject
    }

    override init() { super.init() }

    override func encode(to encoder: Encoder) throws {
        try super.encode(to: encoder)
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(name, forKey: .name)
        try container.encode(age, forKey: .age)
        try container.encode(address, forKey: .address)
        try container.encode(nestedObject, forKey: .nestedObject)
    }

    required init(from decoder: Decoder) throws
    {
        try super.init(from: decoder)
        print(type(of: self))
        print(type(of: decoder))

        let values = try decoder.container(keyedBy: CodingKeys.self)
        print(type(of: values))


        self.name = try values.decode(String.self, forKey: .name)
        self.age = try values.decode(Int.self, forKey: .age)
        self.address = try values.decode(String.self, forKey: .address)
        self.nestedObject = try values.decodeIfPresent(???.self, forKey: .nestedObject)  // HERE i need to know what ???.self is
    }
}

解码为:

let jsonDec = JSONDecoder()
let jsonData = json?.data(using: .utf8)
let decodedContact: Contact = try jsonDec.decode(Contact.self, from: jsonData!)

因此,基本上,当我向服务器发出请求时,我知道接收到的类型(例如,我请求NestedSecondObject),但是如何将其传递给方法“ init(来自decoder:Decoder)”? / p>

我试图扩展JSONDecoder类,并添加一个简单的属性,如下所示:

class EJSONDecoder: JSONDecoder {

    var classType:AnyObject.Type?

}

但是在所需的init(来自解码器:解码器)方法中,解码器的类型不是EJSONDecoder,而是_JSONDecoder,所以我无法访问encode.classType属性。

任何人都可以提供解决方案或某种解决方法的帮助吗? 谢谢!

1 个答案:

答案 0 :(得分:0)

新答案

您可以为解码器提供一个userInfo数组,您可以在其中存储要在解码过程中使用的内容。

let decoder = JSONDecoder()
decoder.userInfo = [.type: type(of: NestedSecondObject.self)]
let decodedContact: Contact = try! decoder.decode(Contact.self, from: json)

extension CodingUserInfoKey {
    static let type = CodingUserInfoKey(rawValue: "Type")!
}

然后在解码时使用它:

switch decoder.userInfo[.type]! {
case let second as NestedSecondObject.Type:
    self.nestedObject = try values.decode(second, forKey: .nestedObject)
case let first as NestedObject.Type:
    self.nestedObject = try values.decode(first, forKey: .nestedObject)
default:
    fatalError("didnt work")
}

可悲的是,我没有找到跳过切换的方法。

旧答案:

解码为

NestedSecondObject.self

,如果失败,则使用

NestedObject.self

。不要捕获NestedObject解码原因,因为即使它无法解码为基本类型,您也会失败。