ProgrammatieSenior iOS ontwikkelaar

Hoe wordt de initialisatie van eigenschappen in Swift uitgevoerd? Wat is het verschil tussen designated, convenience en required initializers? Welke nuances doen zich voor bij het werken met initialisatiehiërarchieën?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord.

In Swift moeten alle eigenschappen van niet-optionele types zijn geïnitialiseerd voor het einde van de initialisatie van het exemplaar. Hiervoor worden initializers gebruikt: designated (basis), convenience (hulp) en required (verplicht voor afgeleiden).

  • Designated initializer - de basis, verantwoordelijk voor het initialiseren van alle eigenschappen van de klasse en het aanroepen van de designated initializer van de superclass. Elke klasse heeft minstens één designated initializer.
  • Convenience initializers - hulp, delegeren de initialisatie aan dezelfde klasse (roepen andere initializers binnen de klasse aan via self.init(...)), wat het creëren van een object met verschillende parametercombinaties vereenvoudigt.
  • Required initializer - vereist dat alle afgeleide klassen deze initializer implementeren. Het wordt gedeclareerd met de required-modifier.

Voorbeeld:

class Vehicle { let numberOfWheels: Int required init(numberOfWheels: Int) { self.numberOfWheels = numberOfWheels } } class Car: Vehicle { let brand: String // Designated initializer required init(numberOfWheels: Int) { self.brand = "Unknown" super.init(numberOfWheels: numberOfWheels) } // Convenience convenience init() { self.init(numberOfWheels: 4) self.brand = "Ford" } }

Kernfeatures:

  • Alle eigenschappen moeten zijn geïnitialiseerd voordat super.init wordt aangeroepen.
  • Convenience initializers moeten altijd designated of een andere convenience initializer via self aanroepen.
  • Required initializers moeten in alle afgeleiden klassen worden geïmplementeerd.

Vragend met een valstrik.

In welke volgorde moeten de eigenschappen van een afgeleide klasse en de superclass worden geïnitialiseerd bij het gebruik van een designated initializer?

Antwoord: Alle eigenschappen van de afgeleide klasse moeten zijn geïnitialiseerd voordat de designated initializer van de superclass (super.init) wordt aangeroepen, anders zal dit een compilatiefout opleveren. Na super.init kunnen nieuwe opgeslagen eigenschappen van de afgeleide klasse niet meer worden geïnitialiseerd, alleen worden gebruikt.

class Parent { let parentProp: Int init(prop: Int) { parentProp = prop } } class Child: Parent { let childProp: String init(prop: Int, childProp: String) { self.childProp = childProp // Eerst eigen eigenschappen super.init(prop: prop) // Dan parent } }

Voorbeelden van echte fouten door onbekendheid met de nuances van het onderwerp.


Verhaal

Een ontwikkelaar probeerde in een convenience initializer rechtstreeks een waarde toe te wijzen aan een vereiste eigenschap zonder de designated aan te roepen. Dit resulteerde in het twee keer initialiseren van de eigenschap met verschillende waarden, wat leidde tot onverwacht gedrag tijdens het testen.


Verhaal

Bij het erven van een diepe klassenhiërarchie vergaten ze de vereiste init te declareren, wat leidde tot de onmogelijkheid om het afgeleide type correct te initialiseren uit een framework via reflectie, en een crash bij het deserialiseren van een JSON-model.


Verhaal

In de applicatie werd de designated initializer van de superclass niet aangeroepen tijdens het uitbreiden van de Vehicle-klasse, wat leidde tot een incorrecte initialisatie van verplichte eigenschappen en een runtime crash in productie na de gegevensschema-update.