1

I'm trying to make inherited data model in order to parse it with JSONDecoder.

class FirstClass : Codable {
    let firstClassProperty: Int
    final let arrayOfInts: [Int]
}

class SecondClass : FirstClass {
    let secondClassProperty1: Int
    let secondClassProperty2: Int

    private enum CodingKeys : String, CodingKey {
        case secondClassProperty1, secondClassProperty2
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        secondClassProperty1 = try container.decode(Int.self, forKey: .secondClassProperty1)
        secondClassProperty2 = try container.decode(Int.self, forKey: .secondClassProperty2)

        try super.init(from: decoder)
    }
}

I use this JSON for FirstClass:

{
    "firstClassProperty":  123,
    "arrayOfInts": [
        123
    ]
}

and this for SecondClass:

{
  "firstClassProperty": {},
  "secondClassProperty1": {},
  "secondClassProperty2": {}
}

How can I get rid of arrayOfInts in my subclass but let it be in superclass if keyword final doesn't work in this case?

Here's Playground. Thanks for your answers!

Paulo Mattos
  • 18,845
  • 10
  • 77
  • 85
solitude3
  • 13
  • 3

2 Answers2

0

A quick hack is to declare it as optional. For instance:

class FirstClas: Codable {
    let firstClassProperty: Int
    final let arrayOfInts: [Int]?
}

That would work around a missing arrayOfInts automatically.

Manual solution. Another solution is to implement the Decodable protocol yourself — as you did in SecondClass — and decode arrayOfInts using decodeIfPresent (and use a default value otherwise).


Superclass decoding. By the way, the recommended way to forward the Decoder to the superclass is by using superDecoder() method:

...
let superDecoder = try container.superDecoder()
try super.init(from: superDecoder)
Paulo Mattos
  • 18,845
  • 10
  • 77
  • 85
  • @LeoDabus I’m [struct junkie](https://developer.apple.com/videos/play/wwdc2015/414/) myself but, without further info from good solitude3 here, I can’t really kill his classes point blank as you say, haha ;) He might need this capability inside a much larger app with a whole unknown set of design constraints... – Paulo Mattos Oct 17 '17 at 01:41
  • @LeoDabus Not really true. A specific `superDecoder()` API, as used in my answer, signals to me that Apple clearly designed this to be used by *classes* as well. There might be some missing bits here and there, but the intention seems clear to me... – Paulo Mattos Oct 17 '17 at 01:49
  • @LeoDabus ...and Apple actually provided a [complete, detailed example in WWDC 2017](https://stackoverflow.com/a/44605696/819340) :-) – Paulo Mattos Oct 17 '17 at 02:00
  • I wouldn’t say so. This question is mainly focused on ignoring a superclass property (and not a full blown discussion about inheritance as the other question). OP really won’t be able to hack a solution by only looking at that other much larger question, IMHO... – Paulo Mattos Oct 17 '17 at 02:08
0

You can use like this :

class FirstClass : Codable {
    let firstClassProperty: Int
    final let arrayOfInts: [Int]?
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        firstClassProperty = try container.decode(Int.self, forKey: .firstClassProperty)
        arrayOfInts = try container.decodeIfPresent([Int].self, forKey: .arrayOfInts)
    }
}
Vini App
  • 7,339
  • 2
  • 26
  • 43
  • If the property is already marked as *optional*, I think the automatically generated code might be enough here — and, by the way, should be quite similar to what you have manually written ;) – Paulo Mattos Oct 17 '17 at 01:20