Swift JSONDecoder - 编码键与下划线无法正常工作

3

请有人解释一下,为什么A部分的代码能正常运行,而B部分不能?让我很困惑。

可运行代码

struct Coded : Codable, Hashable {  
  public let avar1: String
  public let avar2: String

  enum CodingKeys: String, CodingKey {
    case avar1 = "avar1"
    case avar2 = "avar2"
  }

  init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    print (container.allKeys)
    avar1 = try container.decode(String.self, forKey: .avar1)
    avar2 = try container.decode(String.self, forKey: .avar2)
  }
}

let JSONStr = """
{
  "avar1": "This is a string",
  "avar2": "This is a string2",
}
"""

if let jsdata = JSONStr.data(using: .utf8) {
  let decoder = JSONDecoder()
  decoder.keyDecodingStrategy = .convertFromSnakeCase
  let aobj: Coded? = try? decoder.decode(Coded.self, from: jsdata)
  print (aobj ?? "No object")
}

输出

[CodingKeys(stringValue: "avar1", intValue: nil), CodingKeys(stringValue: "avar2", intValue: nil)]
Coded(avar1: "This is a string", avar2: "This is a string2")

无法工作

struct Coded : Codable, Hashable {  
  public let avar1: String
  public let avar2: String

  enum CodingKeys: String, CodingKey {
    case avar1 = "avar1"
    case avar2 = "avar_2"
  }

  init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    print (container.allKeys)
    avar1 = try container.decode(String.self, forKey: .avar1)
    avar2 = try container.decode(String.self, forKey: .avar2)
  }
}

let JSONStr = """
{
  "avar1": "This is a string",
  "avar_2": "This is a string2",
}
"""

if let jsdata = JSONStr.data(using: .utf8) {
  let decoder = JSONDecoder()
  decoder.keyDecodingStrategy = .convertFromSnakeCase
  let aobj: Coded? = try? decoder.decode(Coded.self, from: jsdata)
  print (aobj ?? "No object")
}

输出

[CodingKeys(stringValue: "avar1", intValue: nil)]
No object

第二个函数只会显示编码键,不带下划线。 但是,一旦我去掉下划线,它就会在所有键中具有编码键...
Swift 4.2 - Xcode 10.2.
有什么想法吗?

1
我最终通过关闭我的游乐场并重新启动来解决了这个问题。看起来可能是一个解释器问题... 这太奇怪了。 - Peter Suwara
看起来较大的数据集正在使用.convertFromSnakeCase,这会导致在解码期间编码键消失。 - Peter Suwara
2个回答

4

.convertFromSnakeCasesnake_case 变量转换为 camelCase,然后再访问 CodingKeys

如果您想指定 CodingKeys,则必须在NOT WORKING示例中使用转换后的值。

enum CodingKeys: String, CodingKey {
    case avar1 = "avar1"
    case avar2 = "avar2"
}

然而这展示了 CodingKeys 的无意义。所以反其道而行之,利用键解码策略。

与其移除 .convertFromSnakeCase,不如移除 CodingKeys 和初始化器。

并且始终捕获可能的 Decoding 错误。

struct Coded : Codable {
    public let avar1: String
    public let avar2: String
}

let jsonStr = """
{
"avar1": "This is a string",
"avar_2": "This is a string2",
}
"""

let jsdata = Data(jsonStr.utf8)
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
do {
    let aobj = try decoder.decode(Coded.self, from: jsdata)
    print(aobj)
} catch { print(error) }

感谢分享这个见解,即在访问编码键之前将键转换为驼峰式大小写。我的个人偏好是删除convertFromSnakeCase,因为使用它会混淆JSON变量名与键的绑定关系。 - Peter Suwara

2
我已经解决了这个问题。它源于使用Snake Case时出现的问题。在某些情况下,它可能会导致问题。我不确定问题是什么以及为什么会发生。但是如果您启用了带有Snake Case策略的JSONDecoder,则会删除使用Snake Case编码的项目的KeyCodings。

通过从我的JSONDecoder中删除以下内容,我成功地解决了问题。

如果您设置了此参数并强制将编码字符串转换为Snake Case,则会删除Coding Key字符串,并在解码期间出现错误,请删除以下内容:

如果您的编码键包括

codingKey = "a_json_var"

如果您添加convertFromSnakeCase,这将完全删除编码键。因此,在蛇形大小写的情况下,请不要在编码键案例上指定文本字符串,否则它将会中断。
删除 ->
decoder.keyDecodingStrategy = .convertFromSnakeCase

如果您想准确指定编码密钥文本名称。最初的回答。

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