Swift Codable初始化

Dar*_*rko 5 json swift codable decodable

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

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

    init() {
       name = "\(id) \(name)" 
    }
}
Run Code Online (Sandbox Code Playgroud)

但是我得到了编译器错误:

Return from initializer without initializing all stored properties
Run Code Online (Sandbox Code Playgroud)

这对我很清楚,因为init()希望我初始化所有属性。但是添加具有所有必需属性的init()并不能解决该问题,因为当Codable插入时,此初始化器不会被调用(!):

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

然而,在解码完成之后,是否有一种方法可以执行一些初始化逻辑,而无需为每个属性手动进行所有解码?因此无需每次都执行init(from decoder: Decoder)。在这个简短的示例中,我只有两个简单的属性,但是生产代码包含数千个属性。

谢谢。

vad*_*ian 10

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

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)" 
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以实现,init()但这独立于解码功能而起作用,并且您必须为所有非可选属性分配默认值,这就是错误的含义。


Ger*_*eon 9

使用首先使用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)
Run Code Online (Sandbox Code Playgroud)