Pourquoi utiliser les initialiseurs requirejs dans les classes Swift?

J’essaie de comprendre l’utilisation du mot clé required dans les classes Swift.

 class SomeClass { required init() { // initializer implementation goes here } } 

required ne me force pas à implémenter la méthode dans ma classe enfant. Si je veux remplacer l’initialiseur désigné required de ma classe parente, je dois écrire et ne pas override . Je sais comment cela fonctionne mais je ne peux pas comprendre pourquoi je devrais le faire.

Quel est l’avantage de required ? Autant que je sache, les langages comme C # n’ont pas quelque chose comme ça et fonctionnent parfaitement avec la override .

C’est en fait juste un moyen de satisfaire le compilateur pour lui assurer que si cette classe devait avoir des sous-classes, elle hériterait ou implémenterait ce même initialiseur. Il y a un doute sur ce point, en raison de la règle selon laquelle si une sous-classe a son propre initialiseur, aucun initialiseur de la super-classe n’est hérité . Ainsi, une super-classe peut avoir un initialiseur et une sous-classe pour ne pas l’avoir. required surmonte cette possibilité.

Une des situations où le compilateur doit être satisfait de cette manière implique des protocoles et fonctionne comme ceci:

 protocol Flier { init() } class Bird: Flier { init() {} // comstack error } 

Le problème est que si Bird avait une sous-classe, cette sous-classe devrait implémenter ou hériter d’ init et vous ne l’avez pas garanti. Marquer l’ init de Bird comme required garantit.

Alternativement, vous pourriez marquer Bird comme final , garantissant ainsi l’inverse, à savoir qu’il n’aura jamais une sous-classe.

Une autre situation est celle où vous avez une méthode d’usine qui peut créer une classe ou sa sous-classe en appelant le même initialiseur:

 class Dog { var name: Ssortingng init(name: Ssortingng) { self.name = name } } class NoisyDog: Dog { } func dogMakerAndNamer(whattype: Dog.Type) -> Dog { let d = whattype.init(name: "Fido") // comstack error return d } 

dogMakerAndNamer appelle l’ init(name:) sur la sous-classe Dog ou a Dog. Mais comment le compilateur peut-il être sûr qu’une sous-classe aura un init(name:) ? La désignation required calme les craintes du compilateur.

Je veux attirer l’attention sur une autre solution fournie par Required , à part que Matt a donné ci-dessus.

 class superClass{ var name: Ssortingng required init(){ // initializer implementation goes here self.name = "Untitled" } } class subClass: superClass { var neakName: Ssortingng = "Subclass Untitled" } let instanceSubClass = subClass() instanceSubClass.name //output: "Untitled" instanceSubClass.neakName //output: "Subclass Untitled" 

Comme vous pouvez le vérifier dans l’exemple ci-dessus, j’ai déclaré required init() superClass sur superClass , l’ init() de superClass a hérité par défaut de la sous- subClass , vous pouvez donc créer une instance de subClass let instanceSubClass = subClass() .

Mais, supposons que vous souhaitiez append un initialiseur désigné dans la sous-classe pour atsortingbuer une valeur d’exécution à la propriété stockée neakName . Bien sûr, vous pouvez l’append, mais cela ne fera pas hériter subclass d’initialiseurs de la super-classe . Donc, si vous créez une instance de sous- subClass vous créerez comme ci-dessous son propre initialiseur.

 class superClass{ var name: Ssortingng init(){ // initializer implementation goes here self.name = "Untitled" } } class subClass: superClass { var neakName: Ssortingng = "Subclass Untitled" init(neakName: Ssortingng) { self.neakName = neakName } } let instanceSubClass = subClass(neakName: "Bobby") instanceSubClass.name //output: "Untitled" instanceSubClass.neakName //output: "Bobby" 

Ci-dessus, vous ne pourrez pas créer une instance de subClass par subClass() , mais si vous voulez que chaque sous-classe de superClass ait son propre init() pour créer une instance directe par subClass() . Il suffit de placer le mot-clé required avant init() sur superClass, cela vous obligera à append l’initialiseur d’initialisation init() sur la sous- subClass – comme ci-dessous.

 class superClass{ var name: Ssortingng required init(){ // initializer implementation goes here self.name = "Untitled" } } class subClass: superClass { var neakName: Ssortingng = "Subclass Untitled" init(neakName: Ssortingng) { self.neakName = neakName } } // Comstackr error <------------ required `init()` must be provided by subClass. let instanceSubClass = subClass(neakName: "Bobby") instanceSubClass.name //output: "Untitled" instanceSubClass.neakName //output: "Bobby" 

A ce titre, utilisez le mot-clé required avant l'initialiseur sur la super-classe, lorsque vous souhaitez que toutes les sous-classes doivent avoir été implémentées required initializer de la super-classe.

Selon la documentation :

 Write the required modifier before the definition of a class initializer to indicate that every subclass of the class must implement that initializer 

Donc oui, obligatoire oblige toutes les classes enfants à implémenter ce constructeur. Cependant, ce n’est pas nécessaire

  if you can satisfy the requirement with an inherited initializer. 

Donc, si vous avez créé des classes plus complexes qui ne peuvent pas être entièrement initialisées avec un constructeur parent, vous devez implémenter le constructeur require.

Exemple tiré de la documentation (avec quelques éléments ajoutés):

 class SomeClass { required init() { // initializer implementation goes here } } class SomeSubclass: SomeClass { let thisNeedsToBeInitialized: Ssortingng required init() { // subclass implementation of the required initializer goes here self.thisNeedsToBeInitialized = "default value" } } 

Si vous essayez d’append votre propre initialiseur dans la sous-classe, vous devez suivre certaines choses qui ont été déclarées dans la super classe. Donc, assurez-vous que vous n’oublierez pas de mettre en œuvre cette méthode requirejse. Si vous oubliez que le compilateur vous donnera une erreur // fatal error, we've not included the required init() erreur // fatal error, we've not included the required init() . Une autre raison est que cela crée un ensemble de conditions que chaque sous-classe doit suivre si la sous-classe définit son propre initialiseur.