Home > Back-end >  When decoding a Codable struct from JSON, how do you initialize a property not present in the JSON?
When decoding a Codable struct from JSON, how do you initialize a property not present in the JSON?

Time:05-26

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

  • Related