【问题标题】:Swift Codable Decode Manually Optional VariableSwift Codable Decode 手动可选变量
【发布时间】:2023-12-23 17:08:01
【问题描述】:

我有以下代码:

import Foundation

let jsonData = """
[
    {"firstname": "Tom", "lastname": "Smith", "age": "28"},
    {"firstname": "Bob", "lastname": "Smith"}
]
""".data(using: .utf8)!

struct Person: Codable {
    let firstName, lastName: String
    let age: String?

    enum CodingKeys : String, CodingKey {
        case firstName = "firstname"
        case lastName = "lastname"
        case age
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        firstName = try values.decode(String.self, forKey: .firstName)
        lastName = try values.decode(String.self, forKey: .lastName)
        age = try values.decode(String.self, forKey: .age)
    }

}

let decoded = try JSONDecoder().decode([Person].self, from: jsonData)
print(decoded)

问题是它在age = try values.decode(String.self, forKey: .age) 上崩溃了。当我取出 init 函数时,它工作正常。错误是No value associated with key age (\"age\").

关于如何使它成为可选项并且在它不存在时不让它崩溃的任何想法?由于其他原因,我还需要 init 函数,但只是做了一个简单的例子来解释发生了什么。

【问题讨论】:

标签: swift swift4 codable


【解决方案1】:

年龄是可选的:

let age: String? 

所以尝试这样解码:

let age: String? = try values.decodeIfPresent(String.self, forKey: .age)

【讨论】:

  • 太棒了,非常感谢!! Stack Overflow 不会让我再接受几分钟。当他们让我这样做时会这样做。
【解决方案2】:

在我的模型中,我所做的是

var title: String?

...

title = try container.decode(String?.self, forKey: .age)

而不是

name = try? container.decode(String.self, forKey: .age)

例如,出于某种原因,后端为该键传递了一个数值,例如title: 74。使用第一种方法,你会得到这样的错误信息(我为我的模型写了一个单元测试),你可以快速定位问题

但是,使用第二种方法try?,此有用的错误消息将被静音并且不会冒泡。你仍然会得到一个有效的解码结果title = nil,如果只有来自后端的null 应该产生nil,这在大多数情况下实际上是不正确的。

当然,如果你设计的是无论从后端检索什么,只要类型不匹配,就会是nil。那么我认为第一种方法应该没有任何问题。

【讨论】:

    【解决方案3】:

    iOS 有一个内置方法,仅当值存在时才读取它们。

    变量年龄:字符串?

    age = try container.decodeIfPresent(String.self, forKey: .age)

    【讨论】:

    • 这比其他答案有什么好处?
    【解决方案4】:

    这对我有用。

    var age: String? = nil
    age = try? container.decode(String.self, forKey: .age)
    

    希望得到帮助。

    【讨论】:

    • 这是错误的,try? 只是忽略任何错误而不解决真正的问题,应该改用decodeIfPresent
    • throws: DecodingError.typeMismatch if the encountered encoded value
    • @user25917 - 那是另一回事。自尝试以来,那行代码永远不会抛出错误吗?在这种情况下,只是解析为 nil 而不是抛出。如果您仍然感到困惑,请查看 try catch 错误处理的工作原理。