Home > database >  Decodable with extra property
Decodable with extra property

Time:10-02

I have a Decodable to which I want to add one extra property, not present in the plist.

The code below seems to work. I'm not sure why, since it no longer conforms to the plist. Can anyone explain?

Is there any better of doing it without having to write a custom init and CodingKeys?

struct Phrases: Decodable {
  let animal: Dictionary<String, String>
  let clothes: Dictionary<String, String>
  let food: Dictionary<String, String>
  let color: Dictionary<String, String>
}

extension Phrases {
  var nouns: Dictionary<String, String> {
    var nouns = [String: String]()
    nouns  = self.animal
    nouns  = self.clothes
    nouns  = self.food
    return nouns
  }
}

extension Dictionary {
  static func  = (left: inout Dictionary, right: Dictionary) {
    left.merge(right) { $1 }
  }
}

CodePudding user response:

This new property that you have added is a computed property, not a stored property like animal, food, etc

The synthesised Decodable implementation is only derived from the stored properties of the struct, so adding a computed property does not change the synthesised Decodable implementation at all.

This is because the semantics of computed property is that its value is computed every time you access it (call its getter). Every time you say nouns, the code in the body runs, creating a new dictionary by computing the merge of the two dictionaries. This is as if it were just a function:

func nouns() -> Dictionary<String, String> {
    var nouns = [String: String]()
    nouns  = self.animal
    nouns  = self.clothes
    nouns  = self.food
    return nouns
}

If that is the semantics you want, then doing this is not problematic at all.


Alternatively, if you want the semantics of a stored property, you can add CodingKeys (but no need for a custom init(from:)) and use a lazy var:

lazy var nouns: [String: String] = {
    ...
}()

enum CodingKeys: CodingKey {
    case animal, food, color, clothes
}

However, this makes nouns mutable, which may not be desirable. To make nouns a stored property and a let, I'm pretty sure you have to write a custom init(from:).

See more differences between this and a computed property in my answer here.

  • Related