Tiendo a poner solo las necesidades (propiedades almacenadas, inicializadores) en las definiciones de mi clase y mover todo lo demás a las suyas extension
, como un extension
bloque lógico con el que también agruparía // MARK:
.
Para una subclase de UIView, por ejemplo, terminaría con una extensión para cosas relacionadas con el diseño, una para suscribirse y manejar eventos, etc. En estas extensiones, inevitablemente tengo que anular algunos métodos UIKit, por ejemplo layoutSubviews
. Nunca noté ningún problema con este enfoque, hasta hoy.
Tome esta jerarquía de clases, por ejemplo:
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 salida es A B C
. Eso tiene poco sentido para mí. Leí sobre las Extensiones de protocolo que se envían estáticamente, pero este no es un protocolo. Esta es una clase regular, y espero que las llamadas a métodos se envíen dinámicamente en tiempo de ejecución. ¿Está claro que la llamada C
al menos debería ser despachada y producida dinámicamente C
?
Si elimino la herencia NSObject
y hago C
una clase raíz, el compilador se queja diciendo declarations in extensions cannot override yet
, sobre lo que ya leí. ¿Pero cómo tener NSObject
como clase raíz cambia las cosas?
Mover ambas anulaciones en su declaración de clase produce A A A
como se esperaba, mover solo B
las producciones A B B
, mover solo A
las producciones C B C
, la última de las cuales no tiene absolutamente ningún sentido para mí: ¡ni siquiera la que está escrita estáticamente para A
producir la A
salida!
Agregar la dynamic
palabra clave a la definición o una anulación parece darme el comportamiento deseado 'desde ese punto en la jerarquía de clases hacia abajo' ...
Cambiemos nuestro ejemplo a algo un poco menos construido, lo que realmente me hizo publicar esta pregunta:
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()
Ahora lo tenemos A B A
. Aquí no puedo hacer que las subvistas de diseño de UIView sean dinámicas de ninguna manera.
Mover ambas anulaciones a su declaración de clase nos lleva de A A A
nuevo, solo A o solo B todavía nos consigue A B A
. dynamic
De nuevo resuelve mis problemas.
En teoría, podría agregar dynamic
a todo override
lo que hago, pero siento que estoy haciendo algo más aquí.
¿Es realmente incorrecto usar extension
s para agrupar código como lo hago?