Swift Codable init

时间:2018-01-16 11:52:39

标签: json swift codable decodable

我想在Swift编码/编码功能完成JSON解码后做一些初始化逻辑。

struct MyStruct: Codable {
    let id: Int 
    var name: String

    init() {
       name = "\(id) \(name)" 
    }
}

但是我收到了编译错误:

Return from initializer without initializing all stored properties

我很清楚,因为init()希望我初始化所有属性。但是添加一个包含所有必需属性的init()也无法解决它,因为当Codable启动时,不会调用此初始值设定项(!):

init(id: Int, name: String) {
    // This initializer is not called if Decoded from JSON!
    self.id = id 
    self.name = "\(id) \(name)" 
}

然而 - 在解码完成后有没有办法做一些初始化逻辑但没有为每个属性手动完成所有解码?所以每次init(from decoder: Decoder)都没有实施。在这个简短的例子中,我只有两个简单的属性,但生产代码由数千个属性组成。

感谢。

2 个答案:

答案 0 :(得分:5)

您可以免费获得所有内容但标准化,或者您必须编写自定义初始化程序,如

struct MyStruct: Codable  {

    let id: Int 
    var name: String

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(Int.self, forKey: .id)
        let decodedName = try container.decode(String.self, forKey: .name)
        name = "\(id) \(decodedName)" 
    }
}

您可以实现init(),但这与解码功能无关,您必须为所有非可选属性分配默认值,这是错误所说的内容。

答案 1 :(得分:3)

使用首先使用init(from:)的工厂方法,然后调用自定义初始化代码

struct Foo: Decodable {
    let name: String
    let id: Int

    var x: String!

    private mutating func finalizeInit() {
        self.x = "\(name) \(id)"
    }

    static func createFromJSON(_ data: Data) -> Foo? {
        guard var f = try? JSONDecoder().decode(Foo.self, from: data) else { 
            return nil 
        }
        f.finalizeInit()
        return f
    }
}

let sampleData = """
    { "name": "foo", "id": 42 }
    """.data(using: .utf8)!
let f = Foo.createFromJSON(sampleData)