Swift

Swiftの構造体に自分で定義したenum型があるとうまくデコードできない→解決

自分で定義したenum型が含まれているstructをJSONからデコードする方法で少し悩んだので、解決方法を共有します。

Type 'Character' does not conform to protocol 'Decodable'

次のように、Characterというstructの中にStatusというenum型のプロパティを定義した場合に、Type 'Character' does not conform to protocol 'Decodable'というエラーが出てビルドができない。なんでだ!と悩みました。

enum Status {
    case normal
    case sleep
    case confuse
}

struct Character: Decodable {
    let name: String
    let attack: Int
    let defence: Int
    let status: Status
}

自分で定義したenum型もDecodableにする

上述のビルドエラーを解消するには、StatusDecodableを継承させます。

import Foundation

enum Status: Decodable {
    case normal
    case sleep
    case confuse
}

struct Character: Decodable {
    let name: String
    let attack: Int
    let defence: Int
    let status: Status
}

Decodableとして定義したstructに含まれるプロパティもまた、Decodableを実装している必要があるというルールによるものです。

デコード時にエラー

StatusDecodableを継承させることでビルドエラーは消えますが、実際にJSONDecoderなどを使ってデコードしてみると、うまくいきません。

let json = """
{
    "name": "jimaru",
    "attack": 2,
    "defence": 3,
    "status": "sleep"
}
""".data(using: .utf8)!


let decoder = JSONDecoder()
let character = try! decoder.decode(Character.self, from: json)
// 次のエラーが発生:
// 'try!' expression unexpectedly raised an error:
// Swift.DecodingError.typeMismatch(Swift.Dictionary,
// Swift.DecodingError.Context(
// codingPath: [CodingKeys(stringValue: "status", intValue: nil)],
// debugDescription: "Expected to decode Dictionary but found a string instead.",
// underlyingError: nil))

これはJSON内のstatusのデータが何であったらStatus.normalとしてデコードするのか、Status.sleepとしてデコードするのか、という情報が不足しているためです。

StatusrawValueを文字列で設定すれば、このrawValueの値からデコードしてくれるようになります。

enum Status: String, Decodable {
    case normal = "normal"
    case sleep = "sleep"
    case confuse = "confuse"
}

rawValueについてのドキュメントはThe Swift Programming Language > Enumerations > Raw Valuesです。

あとがき

今回の内容は、Apple公式ドキュメントのEncoding and Decoding Custom Typesを発見したことで解決しました。

Decodableプロトコルのページからもリンクが貼ってあったので、真っ先に辿り着くべきページでしたね。。ググって出てきた見当違いの記事を読んでしまったことで頭を抱え、無駄な時間を使ってしまいやした。

この記事により頭を抱える人が減る手助けになりますように。。

-Swift

© 2024 ヂまるBlog