web-dev-qa-db-ja.com

Swift Codable init

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つの単純なプロパティしかありませんが、製品コードは数千のプロパティで構成されています。

ありがとう。

6
Darko

すべてを無料で入手できますが、標準化されているか、次のようなカスタム初期化子を作成する必要があります

_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()を実装できますが、これはデコード機能とは無関係に機能し、オプションではないすべてのプロパティにデフォルト値を割り当てる必要があります。これがエラーです。

13
vadian

最初に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)
4
Gereon