La delega di inizializzazione è un sistema di delega dell'inizializzazione integrato in Swift per le classi. In Swift, c'è una differenza storica tra il designated initializer (inizializzatore principale della classe, responsabile dell'inizializzazione completa di tutte le proprietà) e il convenience initializer (un inizializzatore ausiliario che facilita la creazione di un'istanza con diversi set di parametri).
Problema: se si permette un'esecuzione caotica degli inizializzatori tra classi e i loro eredi, non si può escludere la possibilità che la classe base non sia completamente inizializzata o che l'inizializzazione avvenga più di una volta, portando a un oggetto non valido.
La soluzione è una regola rigorosa:
Esempio di codice:
class Vehicle { var wheels: Int // Designated initializer init(wheels: Int) { self.wheels = wheels } // Convenience initializer convenience init() { self.init(wheels: 4) } } class Car: Vehicle { var color: String // Designated initializer init(wheels: Int, color: String) { self.color = color super.init(wheels: wheels) } // Convenience initializer convenience init(color: String) { self.init(wheels: 4, color: color) } }
Caratteristiche chiave:
Domanda 1: Può un convenience initializer chiamare direttamente l'inizializzatore della superclasse tramite super.init?
No, il convenience initializer delega sempre l'inizializzazione a un altro inizializzatore della classe corrente, che poi può chiamare il designated initializer della superclasse.
Domanda 2: Cosa succede se non si implementa il required initializer nella sottoclasse?
Se la superclasse ha un required initializer, deve essere sovrascritto in ogni sottoclasse (utilizzando required), altrimenti il compilatore genererà un errore.
Domanda 3: Qual è la differenza tra convenience init e convenience required init?
convenience required init è necessario se un determinato convenience initializer è dichiarato come required nella superclasse per garantire il supporto all'inizializzazione nelle gerarchie di ereditarietà.
Un sviluppatore ha chiamato super.init da un convenience initializer. Il codice si compilava solo a causa dell'assenza di determinate restrizioni, ma al momento dell'esecuzione si è verificato un errore: non tutte le proprietà dell'oggetto erano state inizializzate.
Pro:
Contro:
Sono stati utilizzati inizializzatori designated e convenience chiaramente strutturati con chiamate esplicite tra loro. La logica veniva chiamata rigorosamente secondo le regole di Swift, quindi l'inizializzazione era sempre trasparente e corretta.
Pro:
Contro: