在Swift中解码带有关联值的枚举

3

我正在尝试解码一个包含关联值的枚举。我尝试了以下代码,但它一直抛出异常。

let jsonString = """
    {
        "route": "petDetails"
    }
"""

let jsonData = jsonString.data(using: .utf8)

struct Post: Decodable {
    let route: Route
}

enum Route: Decodable, Equatable {
    
    case petDetails(String)

    init?(rawValue: String) {
        switch rawValue {
            case "petDetails":
                self = .petDetails("")
            default:
                return nil
        }
    }
    
    private enum CodingKeys: String, CodingKey {
        case petDetails
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        if let value = try? container.decode(String.self, forKey: .petDetails) {
            self = .petDetails(value)
        } else {
            throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: container.codingPath, debugDescription: "Data doesn't match"))
        }
    }
}


try! JSONDecoder().decode(Post.self, from: jsonData!)

I get the following error:

Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "route", intValue: nil)], debugDescription: "Expected to decode Dictionary<String, Any> but found a string/data instead.", underlyingError: nil))

有什么想法我可能遗漏了吗?


1
你为什么使用了枚举(enum)?你的数据是否可以是多种类型,例如 route 键可以是 Int 或 String 类型? - Rob
帖子有一个路由属性,它是枚举。枚举是路由,可以有许多不同的情况。我从petDetails开始,但它也可以有petProfile、petListing等。 - Mary Doe
1
请您分享一个带有2-3个案例的虚拟 JSON 文件,这将有助于我们更好地理解。 - Rob
1
好的,你的 JSON 应该长这样:route: {"pet_details" : "abc" } ,而不是 route: "petDetails"。它期望解码一个包含该枚举值的字典,但你提供的是一个字符串,所以才会抛出错误。 - Rob
关联的值在哪里?根据JSON和错误信息,它是 let route: String - vadian
显示剩余2条评论
1个回答

1
假设我们有一个带有关联值的枚举:
enum Route: Codable, Equatable {
    case petDetails(name: String)
    case petListing(count: Int)
    ...

表示每个Route的JSON应包含两个值:

  • 告诉我们路线类型的字符串(petDetails vs petListing),以及
  • 相关联的值(名称或计数)。

我们的编码密钥将是

private enum CodingKeys: String, CodingKey {
    case type
    case associatedValue
}

解码函数将会是:

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    let type = try container.decode(String.self, forKey: .type)
    switch type {
        case "petDetails":
            // The associated value is a String
            let name = try container.decode(String.self, forKey: .associatedValue)
            self = .petDetails(name: name)
        case "petListing":
            // The associated value is an Int
            let count = try container.decode(Int.self, forKey: .associatedValue)
            self = .petListing(count: count)
        default:
            throw DecodingError.dataCorruptedError(forKey: .type, in: container, debugDescription: "Invalid type")
    }
}

我们首先解码类型,这告诉我们相关值将是什么类型的数据。


Post的JSON格式如下:

{
    "route": {
        "type": "petDetails",
        "associatedValue": "Rex"
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接