Say that in this example here, this struct
struct Reminder: Identifiable {
var id: String = UUID().uuidString
var title: String
var dueDate: Date
var notes: String? = nil
var isComplete: Bool = false
}
is instead decoded from JSON array values (rather than constructed like in the linked example). If each JSON value were to be missing an "id", how would id
then be initialized? When trying this myself I got an error 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))
.
CodePudding user response:
You can simply use coding keys, like this:
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
}
}
That way, the only properties that will be encoded/decoded are the ones that have a corresponding coding key.
CodePudding user response:
I've also encountered this problem in my own framework ColorKit
I downloaded a 450000 line JSON database from GitHub and found out it has no id
while my SingleColor
model is Identifiable
AHHHHH
So I went to to add id
to them one by one for a couple of days and realized I could actually create a struct
that's without the id
called the SingleColorInit
and load the JSON into this model and then casting all of my data into my SingleColor
model.
Code:
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
}
so when I create a new instance of the object the UUID will be generated.
In your case you can do this:
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
}
And then I realized...
When you use your data in a SwiftUI(if you use it) List
or ForEach
, you don't need it to be Identifiable
; use each item's self
as the id
. Just do this:
List(yourData, id: \.self) { item in
...
}
ForEach(yourData, id: \.self) { item in
...
}
This is problem has annoyed me long time really