【问题标题】:Why does Int enum as dictionary key, produce different json string than Int as dictionary key?为什么将 Int 枚举作为字典键,生成与 Int 作为字典键不同的 json 字符串?
【发布时间】:2021-05-12 19:09:28
【问题描述】:

我尝试用 Int enum 转换字典

enum TypeE: Int, Codable
{
    case note = 1
    case tab
}

let encoder = JSONEncoder()

let dictionary0 = [TypeE.note:"VALUE0", TypeE.tab:"VALUE1"]
var data = try encoder.encode(dictionary0)
var string = String(data: data, encoding: .utf8)!
// [1,"VALUE0",2,"VALUE1"]
print(string)

生成的json字符串输出为

[1,"VALUE0",2,"VALUE1"]

我觉得很奇怪。因为,生成的 json 字符串代表一个数组。


如果我测试了

let encoder = JSONEncoder()

let dictionary1 = [1:"VALUE0", 2:"VALUE1"]
var data = try encoder.encode(dictionary1)
var string = String(data: data, encoding: .utf8)!
// {"1":"VALUE0","2":"VALUE1"}
print(string)

生成的json字符串输出为

{"1":"VALUE0","2":"VALUE1"}

如果我使用 Int 枚举作为字典键,生成的 json 字符串将成为数组的表示?

我的代码有什么错误,还是我的预期不正确?

【问题讨论】:

  • JSON 字典键需要是一个字符串。这很奇怪,但我猜编码器试图修复它,将其转换为数组,但我预计会出现错误。

标签: ios json swift


【解决方案1】:

我为你的案例做了一个扩展可能有用:

extension Dictionary where Key == TypeE.RawValue, Value == String {
    
    init(dictionaryLiteral elements: (TypeE, String)...) {
        var headers: [TypeE.RawValue: String] = [:]
        for pair in elements {
            headers[pair.0.rawValue] = pair.1
        }
        
        self = headers
    }
    
    subscript(typeE t: TypeE) -> Value? {
        get {
            return self[t.rawValue]
        }
        set {
            self[t.rawValue] = newValue
        }
    }
}

用法:

var dic2 = Dictionary<TypeE.RawValue, String>.init(dictionaryLiteral: (TypeE.note,"Str"), (TypeE.tab,"Str2"))

添加新的键/值:

dic2[typeE: TypeE.thirdCase] = "Str3"

O/P:

并获取特定密钥:

【讨论】:

    【解决方案2】:

    Codable 的源代码对此行为进行了解释。如果键不是StringInt,则结果类型为Array

      public func encode(to encoder: Encoder) throws {
        if Key.self == String.self {
          // Since the keys are already Strings, we can use them as keys directly.
          ...
        } else if Key.self == Int.self {
          // Since the keys are already Ints, we can use them as keys directly.
          ...
        } else {
          // Keys are Encodable but not Strings or Ints, so we cannot arbitrarily
          // convert to keys. We can encode as an array of alternating key-value
          // pairs, though.
          var container = encoder.unkeyedContainer()
          for (key, value) in self {
            try container.encode(key)
            try container.encode(value)
          }
        }
      }
    

    【讨论】:

    • 感谢您的指点。但是,我还是不明白,为什么他们不能只使用枚举的rawValue,即Int?如果你明白为什么,介意解释一下吗?
    • 我假设编写实现的人决定忽略KeyRawRepresentableKey.RawValue == Int(或String))的情况。需要来自斯威夫特团队。
    • 更一般的说明 - 复杂的 Codable 对象不能成为键,因为这不是有效的 json 对象:{ {"complex_obj": 1}: "value" }
    猜你喜欢
    • 1970-01-01
    • 2017-07-19
    • 2019-06-29
    • 2014-02-07
    • 2010-11-29
    • 1970-01-01
    • 1970-01-01
    • 2018-10-30
    相关资源
    最近更新 更多