Considérez les deux classes:
class A {
var x: Int
init(x: Int) {
self.x = x
}
convenience init() {
self.init(x: 0)
}
}
class B: A {
init() {
super.init() // Error: Must call a designated initializer of the superclass 'A'
}
}
Je ne vois pas pourquoi ce n'est pas autorisé. En fin de compte, l'initialiseur désigné de chaque classe est appelée avec toutes les valeurs dont ils ont besoin, alors pourquoi dois - je me répéter dans B
« s init
en spécifiant une valeur par défaut de x
nouveau, lorsque la commodité init
en A
fera très bien?
class
initialization
swift
Robert
la source
la source
Réponses:
Il s'agit de la règle 1 des règles "Initializer Chaining" comme spécifié dans le Guide de programmation Swift, qui se lit comme suit:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html
Soulignez le mien. Les initialiseurs désignés ne peuvent pas appeler les initialiseurs pratiques.
Il existe un diagramme qui accompagne les règles pour montrer quelles "directions" d'initialisation sont autorisées:
la source
SCNGeometry
: vous pouvez ajouter desSCNGeometryElement
s uniquement en utilisant l'initialiseur de commodité, donc on ne peut pas en hériter.Considérer
Étant donné que tous les initialiseurs désignés de la classe A sont remplacés, la classe B héritera de tous les initialiseurs de commodité de A. Donc, l'exécution de ceci produira
Maintenant, si l'initialiseur désigné B.init (a: b :) était autorisé à appeler l'initialiseur de commodité de classe de base A.init (a :), cela entraînerait un appel récursif à B.init (a:, b: ).
la source
C'est parce que vous pouvez vous retrouver avec une récursion infinie. Considérer:
et regardez:
qui appellera
SubClass.init()
qui appelleraSuperClass.init(value:)
qui appelleraSubClass.init()
.Les règles d'initialisation désignées / pratiques sont conçues pour qu'une initialisation de classe soit toujours correcte.
la source
J'ai trouvé une solution pour cela. Ce n'est pas super joli, mais cela résout le problème de ne pas connaître les valeurs d'une superclasse ou de vouloir définir des valeurs par défaut.
Tout ce que vous avez à faire est de créer une instance de la superclasse, en utilisant la commodité
init
, directement dansinit
la sous-classe. Ensuite, vous appelez le désignéinit
du super en utilisant l'instance que vous venez de créer.la source
Pensez à extraire le code d'initialisation de votre pratique
init()
vers une nouvelle fonction d'assistancefoo()
, appelezfoo(...)
pour effectuer l'initialisation dans votre sous-classe.la source
Regardez la vidéo WWDC "403 intermediaire Swift" à 18h30 pour une explication détaillée des initialiseurs et de leur héritage. D'après ce que j'ai compris, considérez ce qui suit:
Mais maintenant, considérez une sous-classe Wyrm: Un Wyrm est un Dragon sans pattes et sans ailes. Donc l'initialiseur pour un Wyvern (2 pattes, 2 ailes) est faux! Cette erreur peut être évitée si la commodité Wyvern-Initializer ne peut tout simplement pas être appelée, mais uniquement l'initialiseur désigné complet:
la source
initWyvern
crée une sous-classe quand il est logique d'être appelé?Wyrm
de remplacer le nombre de segments après avoir appelé un initialiseur de commodité.Pourquoi n'avez-vous pas simplement deux initialiseurs - un avec une valeur par défaut?
la source