子类化swift通用可解码类型

时间:2018-03-28 17:14:57

标签: ios json swift decodable

编辑:作为Rob Napier wrote,Xcode 9.2中存在问题。在Xcode 9.3中,问题已不再适用。

我的服务器json响应全部打包在data对象中:

{ 
    "data": {...}
}

所以我有以下泛型类型来解析JSON:

class DataContainer<T: Decodable>: Decodable {

    let data: T

    init(data: T)
        self.data = data
    }
}

大部分时间它工作正常,但有一个响应,我还需要解析included字段,所以我创建了SpecificDataContainer子类:

class SpecificDataContainer: DataContainer<DataObject> {
    let included: [IncludedObject]

    init() {
        included = []
        super.init(data: DataObject(id: ""))
    }
}

上面的实现给了我编译器错误'required' initializer 'init(from:)' must be provided by subclass of 'DataContainer'

我在init(from:)中实现了SpecificDataContainer,但编译器仍然给出了同样的错误。

我似乎错过了一些明显的东西。我究竟做错了什么?这是我的完整代码:

import Foundation

let jsonData = """
{
    "data": {
        "id": "some_id"
    },
    "included": [
        {
            "id": "some_id2"
        }
    ]
}
""".data(using:.utf8)!

struct DataObject: Decodable {
    let id: String
}

struct IncludedObject: Decodable {
    let id: String
}

class DataContainer<T: Decodable>: Decodable {
    let data: T

    init(data: T) {
        self.data = data
    }
}

class SpecificDataContainer: DataContainer<DataObject> {
    let included: [IncludedObject]

    init() {
        included = []
        super.init(data: DataObject(id: ""))
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        var includedArray = try container.nestedUnkeyedContainer(forKey: .included)

        var includedObjects:[IncludedObject] = []
        while !includedArray.isAtEnd {
            let includedObject = try includedArray.decode(IncludedObject.self)
            includedObjects.append(includedObject)
        }
        self.included = includedObjects

        try super.init(from: decoder)
    }

    private enum CodingKeys: String, CodingKey {
        case data = "data"
        case included = "included"
    }
}

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
if let obj = try? decoder.decode(SpecificDataContainer.self, from: jsonData) {
    print("object id \(obj.data.id)")
} else {
    print("Fail!")
}

2 个答案:

答案 0 :(得分:2)

由于某些原因,Xcode无法识别init(from:)子类中自动生成的Codable(因为Rob说它可能是一个错误)。在Xcode 9.3发布之前,您可以通过将初始化程序添加到基类来解决此问题:

class DataContainer<T: Decodable>: Decodable {

let data: T

enum CodingKeys: String, CodingKey {
    case data
}

required init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    data = try container.decode(T.self, forKey: .data)
}

答案 1 :(得分:0)

这似乎是Xcode 9.2中的一个错误。在9.3b4你的代码很好。