4

If we encoded objects of a Class that conforms to Codable and would like to decode these objects using a new class code that has a new property, what code would be required to make that new property non-optional, and give it property a default value?

Old class:

class Item: Codable {
    let id: String
}

New class:

class Item: Codable {
    let id: String
    let title: String
}

When decoding objects saved in the old format using the new format's code, no title property will be found, and decoding will not work.

We could fix that by making title an optional String?.

But how would we achieve keeping title as a non-optional String, and giving it a default value when decoding each object?

PS: This is the full code. No Coding Keys were specified, and no custom init from decoder written.

Kqtr
  • 5,824
  • 3
  • 25
  • 32
  • 1
    You have to implement CodingKeys and `init(from decoder` with `decodeIfPresent`. The protocol extension synthesizes (aka requires) each available property. – vadian Sep 02 '19 at 17:41
  • Why would you want to store a value that will always be the same default value. Just display it to the user when reading those values and leave it nil. – Leo Dabus Sep 02 '19 at 18:59
  • @LeoDabus The default value will only be applied to decoded objects that were encoded using the old format. – Kqtr Sep 03 '19 at 10:32

1 Answers1

7

You can implement required init and give it a default value:

required init(from decoder: Decoder) throws {

    let container = try decoder.container(keyedBy: CodingKeys.self)

    let title = try container.decodeIfPresent(String.self, forKey: .title) ?? "Default title"
    self.title = title

    let baseDecoder = try container.superDecoder(forKey: .id)

    try super.init(from: baseDecoder)
}
Kqtr
  • 5,824
  • 3
  • 25
  • 32
andesta.erfan
  • 972
  • 2
  • 12
  • 30
  • 2
    Or perhaps replace that whole `if let`-`else` statement with `nil`-coalescing operator: `title = try container.decodeIfPresent(String.self, forKey: .title) ?? "Default title"`. – Rob Sep 02 '19 at 18:15
  • @andesta.erfan thanks! I had tried that, unsuccessfully. Can this custom init be added later on, when implementing the new format, or should it be present when the first format is implemented? – Kqtr Sep 03 '19 at 10:28
  • @andesta.erfan And should we edit your answer to include a decoding line for the "id" property, or is that line not needed? – Kqtr Sep 03 '19 at 10:35
  • @Kqtr see the edited answer – andesta.erfan Sep 03 '19 at 10:54
  • @andesta.erfan this is really interesting, and I couldn't fin it in other SO threads. Thank you for your time! – Kqtr Sep 05 '19 at 14:08