【问题标题】:Decoding an Enum in Swift with Associated Values在 Swift 中使用关联值解码枚举
【发布时间】:2022-06-16 23:16:58
【问题描述】:

我正在尝试解码由关联值组成的枚举。我正在尝试以下方法,但它不断抛出异常。

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!)

我收到以下错误:

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))

任何想法我缺少什么?

【问题讨论】:

  • 你为什么选择enum?您的数据可以是多种类型,例如 route 键的 Int 和 String 吗?
  • Post 有一个路由属性,它是枚举。 Enum 是 Route,它可以有许多不同的情况。我从 petDetails 开始,但它可以有 petProfile、petListing 等。
  • 你能分享一个假人JSON 2-3 箱吗?这将有助于我们了解更多。
  • 这是一个更大的应用程序的一部分。我只是想为应用程序的一小部分解决这个解码错误。
  • 好的,你的JSON 应该是这样的:route: {"pet_details" : "abc" } 而不是route: "petDetails。它期望使用该枚举解码字典,并且您提供了String,这就是它抛出错误的原因。

标签: ios swift


【解决方案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"
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多