1. ホーム
  2. json

[解決済み] Swift 4 の JSONDecoder で、見つからないキーは、オプションのプロパティである必要はなく、デフォルト値を使うことができますか?

2022-05-01 18:31:29

質問

Swift 4 では、新しい Codable というプロトコルがあります。を使うときは JSONDecoder のオプションでないプロパティをすべて要求するようです。 Codable クラスがJSONにキーを持つかどうかで、エラーがスローされます。

私のクラスのすべてのプロパティをオプションにすることは、不必要な手間のように思えます。(プロパティがnilであることは望んでいません)。

このような方法はあるのでしょうか?

class MyCodable: Codable {
    var name: String = "Default Appleseed"
}

func load(input: String) {
    do {
        if let data = input.data(using: .utf8) {
            let result = try JSONDecoder().decode(MyCodable.self, from: data)
            print("name: \(result.name)")
        }
    } catch  {
        print("error: \(error)")
        // `Error message: "Key not found when expecting non-optional type
        // String for coding key \"name\""`
    }
}

let goodInput = "{\"name\": \"Jonny Appleseed\" }"
let badInput = "{}"
load(input: goodInput) // works, `name` is Jonny Applessed
load(input: badInput) // breaks, `name` required since property is non-optional

解決方法は?

私が好むアプローチは、いわゆるDTO(データトランスファーオブジェクト)を使うことです。 これは、Codableに準拠した構造体で、目的のオブジェクトを表します。

struct MyClassDTO: Codable {
    let items: [String]?
    let otherVar: Int?
}

そして、そのDTOでアプリで使いたいオブジェクトをinitするだけです。

 class MyClass {
    let items: [String]
    var otherVar = 3
    init(_ dto: MyClassDTO) {
        items = dto.items ?? [String]()
        otherVar = dto.otherVar ?? 3
    }

    var dto: MyClassDTO {
        return MyClassDTO(items: items, otherVar: otherVar)
    }
}

この方法は、最終的なオブジェクトを好きなようにリネームして変更できるのも良い点です。 また、手動でデコードするよりもコードが少なくて済みます。 さらに、この方法では、ネットワーク層を他のアプリから分離することができます。