-1

I usually use structs that inherit from Decodable to serialize JSON data i'm pulling from my backend. However, I have an application where a JSON payload is identical to an existing struct with a few minor differences. Thus, I would like to have a decodable struct that inherits from another decodable struct like this:

class Party: Decodable {
    var theme: String

}

class PublicParty : Party {
    var address: String = ""
}

However, when I send the following JSON payload, only "theme" from the Party class gets decoded while the "address" from PublicParty remains "":

{
"theme": "Black out or get out",
"address": "404 Mundus, Tabasko Beach 45778 WA"
}

Swift code:

func test(completion: @escaping(Result<PublicParty, Error>) -> ()) {
        guard let url = URL(string: "127.0.0.1:8000/test") else { return }

        URLSession.shared.dataTask(with: url) { (data, response, error) in

            // handle error
            if let error = error {
                completion(.failure(error))
                return
            }

            // decode data
            do {
                let search = try JSONDecoder().decode(PublicParty.self, from: data!)
                    print(search)
                completion(.success(search))
            } catch let error {
                completion(.failure(error))
            }

        }.resume()

}

As nothing is off in my front end/back end, does Swift even allow this functionality?

  • Structs do not "inherit" from anything, a protocol like Decodable cannot be inherited from, and a `class` like your Party is not a struct. Please use language that has meaning. – matt Jun 05 '20 at 00:27
  • Accepted answer on this thread should help: https://stackoverflow.com/questions/48238196/inheritance-of-encodable-class – rs7 Jun 05 '20 at 00:33
  • Common serialization formats like CSV, JSON and YAML have no notion of inheritance. Swift isn't opinionated on this, and it doesn't introduce its own convention for demarking the type of an object, and where it stands in a hierarchy. If you want to have a JSON payload with a `"theme"`, and `"address"` key to be a `PublicParty` but an object with just a `"theme"` to be a `Party`, then that's something you're going to need to implement yourself. – Alexander Jun 05 '20 at 01:50
  • There are many different ways to do this, with differing trade offs. Here are some ideas: **1)** The type of an object for a particular endpoint always has a single, known type **2)** the payload has a field like `__type` which carries some identifier, which signals to your app which app it should decode by. YAML supports this more natively, with its `! myClass` type annotation syntax. **3)** you can inspect the keys of the object, and decide the type for a particular set of keys. – Alexander Jun 05 '20 at 01:54
  • You;'re completely right, thank you. However, I got inheritance to work, see the solution. @Alexander-ReinstateMonica – Ludovico Verniani Jun 05 '20 at 01:57
  • @LudovicoVerniani Well that doesn't exactly solve the problem you mention, as I understand it. This is approach 1 that I lay out above. You're *always* decoding a `PublicParty`, even if there's no address, in which case you have a non-sensical value of `""` for address – Alexander Jun 05 '20 at 02:49

1 Answers1

0

This worked:

class Party: Decodable {
    var theme: String

}

class PublicParty : Party {
    var address: String = ""

     required init(from decoder: Decoder) throws {

        try super.init(from: decoder)

        let values = try decoder.container(keyedBy: CodingKeys.self)
        address = try values.decode(String.self, forKey: .address)
      }

    private enum CodingKeys: String, CodingKey
    {
        case address

    }
}