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)).
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.
Previous answer is nice.
To have full control, you need to override the default decoding.
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)
}
}
I go a little bit beyond the question, but why is id not set in the JSON?
id is a database key, then it must be present in the json.id is a unique identifier to identify items in UI, then it is much safer and clean to use a dedicated object that describes the object representation.struct ReminderItem: Identifiable {
let id = UUID()
let reminder: Reminder
}
By the way, it works the same way for encoding.
https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With