J'ai tendance à ne mettre que les nécessités (propriétés stockées, initialiseurs) dans mes définitions de classe et à déplacer tout le reste dans les leurs extension
, un peu comme un extension
bloc logique avec lequel je grouperais // MARK:
également.
Pour une sous-classe UIView par exemple, je finirais avec une extension pour les trucs liés à la mise en page, une pour l'abonnement et la gestion des événements, etc. Dans ces extensions, je dois inévitablement remplacer certaines méthodes UIKit, par exemple layoutSubviews
. Je n'ai jamais remarqué de problèmes avec cette approche - jusqu'à aujourd'hui.
Prenez cette hiérarchie de classes par exemple:
public class C: NSObject {
public func method() { print("C") }
}
public class B: C {
}
extension B {
override public func method() { print("B") }
}
public class A: B {
}
extension A {
override public func method() { print("A") }
}
(A() as A).method()
(A() as B).method()
(A() as C).method()
La sortie est A B C
. Cela n'a pas de sens pour moi. J'ai lu que les extensions de protocole étaient distribuées statiquement, mais ce n'est pas un protocole. Il s'agit d'une classe régulière, et je m'attends à ce que les appels de méthode soient distribués dynamiquement au moment de l'exécution. Il est clair que l'appel en cours C
devrait au moins être distribué et produit de manière dynamique C
?
Si je supprime l'héritage NSObject
et crée C
une classe racine, le compilateur se plaint en disant declarations in extensions cannot override yet
, ce que j'ai déjà lu. Mais comment le fait d'avoir NSObject
comme classe racine change-t-il les choses?
Déplacer les deux surcharges dans leur déclaration de classe produit A A A
comme prévu, déplacer uniquement B
les produits A B B
, déplacer uniquement A
les produits C B C
, dont le dernier n'a absolument aucun sens pour moi: même pas celui typé statiquement pour A
produire le A
-output!
L'ajout du dynamic
mot - clé à la définition ou un remplacement semble me donner le comportement souhaité `` à partir de ce point dans la hiérarchie des classes vers le bas '' ...
Changeons notre exemple en quelque chose d'un peu moins construit, ce qui m'a fait poser cette question:
public class B: UIView {
}
extension B {
override public func layoutSubviews() { print("B") }
}
public class A: B {
}
extension A {
override public func layoutSubviews() { print("A") }
}
(A() as A).layoutSubviews()
(A() as B).layoutSubviews()
(A() as UIView).layoutSubviews()
Nous obtenons maintenant A B A
. Ici, je ne peux en aucun cas rendre le layoutSubviews de UIView dynamique.
Déplacer les deux remplacements dans leur déclaration de classe nous A A A
ramène, seuls les A ou seulement les B nous obtiennent encore A B A
. dynamic
résout à nouveau mes problèmes.
En théorie, je pourrais ajouter dynamic
à tout ce que override
je fais mais j'ai l'impression de faire quelque chose de mal ici.
Est-ce vraiment mal d'utiliser extension
s pour grouper du code comme je le fais?