Swift Codable解码手动可选变量

时间:2017-10-13 10:57:46

标签: swift swift4 codable

我有以下代码:

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函数,但只是举了一个简单的例子来解释发生了什么。

4 个答案:

答案 0 :(得分:42)

年龄是可选的:

let age: String? 

所以尝试以这种方式解码:

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

答案 1 :(得分:0)

这对我有用。

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

希望得到帮助。

答案 2 :(得分:0)

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

var title: String?

...

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

而不是

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

例如,出于某种原因,后端会为该键传递一个数字值,例如title: 74。使用第一种方法,您将收到这样的错误消息(我为我的模型编写了单元测试),并且可以快速查明问题

enter image description here

但是,使用第二种方法try?时,此有用的错误消息将被静音并且不会冒泡。您仍将获得有效的解码结果title = nil,如果应该仅从后端获取null,则在大多数情况下实际上是不正确的。

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

答案 3 :(得分:-1)

iOS 有一个内置方法来读取存在的值。

变量年龄:字符串?

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