Swift Codable init

不羁的心 提交于 2019-12-06 02:52:16

问题


I would like to do some initialization logic after the Swift Coding/Encoding feature has finished decoding a JSON.

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

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

But I get the compiler error:

Return from initializer without initializing all stored properties

Which is clear to me because init() wants me to initialise all properties. But adding an init() with all needed properties also doesn't solve it because this initializer is not called(!) when Codable kicks in:

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

Nevertheless - is there a way to do some initialisation logic after the Decoding has finished but without doing all the decoding manually for each property? So without implementing every time init(from decoder: Decoder). In this short example I have just two simple properties but production code consists of thousands of them.

Thanks.


回答1:


Either you get everything for free but standardized or you have to write a custom initializer like

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)" 
    }
}

You can implement init() but this works independent of the decoding functionality and you have to assign a default value to all non-optional properties, that's what the error says.




回答2:


Use a factory method that first uses init(from:) and then calls your custom initialization code

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)


来源:https://stackoverflow.com/questions/48280631/swift-codable-init

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!