Superclass - subclass - init(from: decoder Decoder) - how to

Hello together,

i want to us some classes to manage informations, which get fetched from a firestore database. My idea was, that I will have different classes for the different state of informations. The information which will be common for the different states should have the same properties. Therefore it made sense for me to have a super class which stores the main informations and derive a subclass with extra properties to store the more informations.

My question is, how to define the initializer method properly, so that I can store these data informations fetched from firestore at once without any loss.

Superclass (I reduced it to a minimum, just to show my principal problem):

class GameInfo: Codable, Identifiable {
    @DocumentID var id: String?             // -> UUID of firestore document
    var league: String
    var homeTeam: String
    var guestTeam: String
    
    enum CodingKeys: String, CodingKey {
        case league
        case homeTeam
        case guestTeam
    }
    
    init(league: String, homeTeam: String, guestTeam: String) {
        self.league = league
        self.homeTeam = homeTeam
        self.guestTeam = guestTeam
    }
}

the subclass should contain the GameInfo Properties and some others ...

class Game: GameInfo {
    var startTime: Date?
    
    enum CodingKeys: String, CodingKey {
        case startTime
    }
    
    init(league: String, homeTeam: String, guestTeam: String,  startTime: Date) {
        self.startTime = startTime
        super.init(league: league, homeTeam: homeTeam, guestTeam: guestTeam)
    }
    
    required init(from decoder: any Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        self.startTime = try values.decodeIfPresent(Date.self, forKey: .startTime)

        super.init(league: "", homeTeam: "",, guestTeam: "")
    }

With the required init-method, informations get decoded and stored. (the data from firestore contain the league, homeTeam, guestTeam and startTime informations). The super.init() method as defined results in empty strings. But what I want is, that the league, homeTeam and guestTeam values will also be decoded from the firestore informations. But I don't know how. If I use the code

super.init(league: league, homeTeam: homeTeam, guestTeam: guestTeam)

within the required init() than I get the compiler error message

'self' used in property access 'league' before 'super.init' call

What is wrong in my thinking ? Any help appreciated.

Thanks and best regards

Peter

Replies

If I use the code super.init(league: league, homeTeam: homeTeam, guestTeam: guestTeam) within the required init()

The other init (init(league: String, homeTeam: String, guestTeam: String, startTime: Date)) works because it receives the information such as league via parameters, which are effectively local variables in that initializer.

In this init, there are no such local variables, so super.init(league: league, homeTeam: homeTeam, guestTeam: guestTeam) would actually mean:

super.init(league: self.league, homeTeam: self.homeTeam, guestTeam: self.guestTeam)

That doesn't work, because those three properties are not initialized to anything yet — that's what the super call is for.

If you can decode this information directly from the decoder, like you do for startTime, then you can pass those decoded values into init(league: String, homeTeam: String, guestTeam: String, startTime: Date).

Does that explanation make sense?