从 JSON 解码 Codable 结构时,如何初始化 JSON 中不存在的 属性?
When decoding a Codable struct from JSON, how do you initialize a property not present in the JSON?
说在this example here中,这个结构
struct Reminder: Identifiable {
var id: String = UUID().uuidString
var title: String
var dueDate: Date
var notes: String? = nil
var isComplete: Bool = false
}
改为从 JSON 数组值解码(而不是像链接示例中那样构造)。如果每个 JSON 值都缺少一个“id”,那么 id
将如何初始化?我自己尝试时出现错误 keyNotFound(CodingKeys(stringValue: "id", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"id\", intValue: nil) (\"id\").", underlyingError: nil))
.
您可以简单地使用编码键,如下所示:
struct Reminder: Identifiable, Codable {
var id: String = UUID().uuidString
var title: String
var dueDate: Date
var notes: String? = nil
var isComplete: Bool = false
enum CodingKeys: String, CodingKey {
case title
case dueDate
case notes
case isComplete
}
}
这样,只有具有相应编码键的属性才会 encoded/decoded。
我自己的框架也遇到过这个问题ColorKit
我从 GitHub 下载了一个 450000 行 JSON 的数据库,发现它没有 id
而我的 SingleColor
模型是 Identifiable
啊啊啊啊
所以我花了几天时间将 id
一个一个地添加到它们中,并意识到我实际上可以创建一个没有 id
的 struct
,称为 SingleColorInit
并加载JSON 到这个模型中,然后将我所有的数据转换到我的 SingleColor
模型中。
代码:
public struct SingleColorInit: Codable, Hashable{
public var name: String
public var hex: String
public var rgb: RGBList
public var hsl: HSLList
public var luminance: Double
}
public struct SingleColor: Codable, Hashable, Identifiable{
public var id: UUID = UUID()
public var name: String
public var hex: String
public var rgb: RGBList
public var hsl: HSLList
public var luminance: Double
}
let coloKey: [InitColor] = load("database.json")
public func database() -> [SingleColor] {
var returnData: [SingleColor] = []
for datum in colorKey {
returnData.append(SingleColor(name: datum.name, hex: datum.hex, rgb: datum.rgb, hsl: datum.hsl, luminance: datum.luminance))
}
returnData.remove(at: 0)
return returnData
}
所以当我创建对象的新实例时,将生成 UUID。
在您的情况下,您可以这样做:
struct InitReminder {
var title: String
var dueDate: Date
var notes: String? = nil
var isComplete: Bool = false
}
struct Reminder: Identifiable {
var id: String = UUID().uuidString
var title: String
var dueDate: Date
var notes: String? = nil
var isComplete: Bool = false
}
// load your data (I use the load method in Apple's SwiftUI tutorial)
let reminders: [Reminder] = load("youdatabase.json")
func database() -> [Reminder] {
var returnData: [Reminder] = []
for datum in reminders{
returnData.append(Reminder(title: datum.title, dueDate: datum.dueDate, notes: datum.notes, isComplete: datum.isComplete))
}
return returnData
}
然后我意识到...
当你在 SwiftUI 中使用你的数据时(如果你使用它)List
或 ForEach
,你不需要它是 Identifiable
;使用每个项目的 self
作为 id
。只需这样做:
List(yourData, id: \.self) { item in
...
}
ForEach(yourData, id: \.self) { item in
...
}
这个问题困扰了我很长时间,我真的很高兴与需要它的人分享这个解决方案
真烦人
希望对你有帮助
之前的回答不错
要获得完全控制,您需要覆盖默认解码。
struct Reminder: Identifiable {
var id: String = UUID().uuidString
var title: String
var dueDate: Date
var notes: String? = nil
var isComplete: Bool = false
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
id = (try? values.decode(String.self, forKey: .id)) ?? UUID()
title = try values.decode(String.self, forKey: . title)
dueDate = try values.decode(Date.self, forKey: . dueDate)
notes = try? values.decode(String.self, forKey: .notes)
isComplete = try values.decode(Bool.self, forKey: . isComplete)
}
}
我问的有点过了,但是为什么 JSON 中没有设置 id
?
- 如果
id
是数据库键,则它必须出现在 json 中。
- 另一方面,如果
id
是识别 UI 中项目的唯一标识符,那么使用描述对象表示的专用对象会更安全、更干净。
struct ReminderItem: Identifiable {
let id = UUID()
let reminder: Reminder
}
顺便说一句,它的编码方式相同。
说在this example here中,这个结构
struct Reminder: Identifiable {
var id: String = UUID().uuidString
var title: String
var dueDate: Date
var notes: String? = nil
var isComplete: Bool = false
}
改为从 JSON 数组值解码(而不是像链接示例中那样构造)。如果每个 JSON 值都缺少一个“id”,那么 id
将如何初始化?我自己尝试时出现错误 keyNotFound(CodingKeys(stringValue: "id", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"id\", intValue: nil) (\"id\").", underlyingError: nil))
.
您可以简单地使用编码键,如下所示:
struct Reminder: Identifiable, Codable {
var id: String = UUID().uuidString
var title: String
var dueDate: Date
var notes: String? = nil
var isComplete: Bool = false
enum CodingKeys: String, CodingKey {
case title
case dueDate
case notes
case isComplete
}
}
这样,只有具有相应编码键的属性才会 encoded/decoded。
我自己的框架也遇到过这个问题ColorKit
我从 GitHub 下载了一个 450000 行 JSON 的数据库,发现它没有 id
而我的 SingleColor
模型是 Identifiable
啊啊啊啊
所以我花了几天时间将 id
一个一个地添加到它们中,并意识到我实际上可以创建一个没有 id
的 struct
,称为 SingleColorInit
并加载JSON 到这个模型中,然后将我所有的数据转换到我的 SingleColor
模型中。
代码:
public struct SingleColorInit: Codable, Hashable{
public var name: String
public var hex: String
public var rgb: RGBList
public var hsl: HSLList
public var luminance: Double
}
public struct SingleColor: Codable, Hashable, Identifiable{
public var id: UUID = UUID()
public var name: String
public var hex: String
public var rgb: RGBList
public var hsl: HSLList
public var luminance: Double
}
let coloKey: [InitColor] = load("database.json")
public func database() -> [SingleColor] {
var returnData: [SingleColor] = []
for datum in colorKey {
returnData.append(SingleColor(name: datum.name, hex: datum.hex, rgb: datum.rgb, hsl: datum.hsl, luminance: datum.luminance))
}
returnData.remove(at: 0)
return returnData
}
所以当我创建对象的新实例时,将生成 UUID。
在您的情况下,您可以这样做:
struct InitReminder {
var title: String
var dueDate: Date
var notes: String? = nil
var isComplete: Bool = false
}
struct Reminder: Identifiable {
var id: String = UUID().uuidString
var title: String
var dueDate: Date
var notes: String? = nil
var isComplete: Bool = false
}
// load your data (I use the load method in Apple's SwiftUI tutorial)
let reminders: [Reminder] = load("youdatabase.json")
func database() -> [Reminder] {
var returnData: [Reminder] = []
for datum in reminders{
returnData.append(Reminder(title: datum.title, dueDate: datum.dueDate, notes: datum.notes, isComplete: datum.isComplete))
}
return returnData
}
然后我意识到...
当你在 SwiftUI 中使用你的数据时(如果你使用它)List
或 ForEach
,你不需要它是 Identifiable
;使用每个项目的 self
作为 id
。只需这样做:
List(yourData, id: \.self) { item in
...
}
ForEach(yourData, id: \.self) { item in
...
}
这个问题困扰了我很长时间,我真的很高兴与需要它的人分享这个解决方案
真烦人
希望对你有帮助
之前的回答不错
要获得完全控制,您需要覆盖默认解码。
struct Reminder: Identifiable {
var id: String = UUID().uuidString
var title: String
var dueDate: Date
var notes: String? = nil
var isComplete: Bool = false
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
id = (try? values.decode(String.self, forKey: .id)) ?? UUID()
title = try values.decode(String.self, forKey: . title)
dueDate = try values.decode(Date.self, forKey: . dueDate)
notes = try? values.decode(String.self, forKey: .notes)
isComplete = try values.decode(Bool.self, forKey: . isComplete)
}
}
我问的有点过了,但是为什么 JSON 中没有设置 id
?
- 如果
id
是数据库键,则它必须出现在 json 中。 - 另一方面,如果
id
是识别 UI 中项目的唯一标识符,那么使用描述对象表示的专用对象会更安全、更干净。
struct ReminderItem: Identifiable {
let id = UUID()
let reminder: Reminder
}
顺便说一句,它的编码方式相同。