Envío rápido a methods anulados en extensiones de subclasss

replace las firmas de methods en extensiones parece producir resultados impnetworkingecibles en ciertos casos. El siguiente ejemplo muestra dos resultados diferentes con un patrón similar.

class A: UIViewController { func doThing() { print("dothing super class") } override func viewDidLoad() { print("viewdidload superclass") super.viewDidLoad() } } class B: A { } extension B { override func doThing() { print("dothing sub class") super.doThing() } override func viewDidLoad() { print("viewdidload subclass") super.viewDidLoad() } } let a: A = B() a.doThing() let vc: UIViewController = B() vc.viewDidLoad() 

Esto imprime:

 dothing super class viewdidload subclass viewdidload superclass 

Puede ver que esto omite la implementación de doThing de doThing cuando se emite como A , sin embargo, incluye ambas implementaciones de viewDidLoad cuando se emite como UIViewController . ¿Es este el comportamiento esperado? Si es así, ¿cuál es la razón de esto?

ENV: Xcode 7.3, Playground

La sorpresa aquí es que el comstackdor permite la anulación en la extensión. Esto no comstack:

 class A { func doThing() { print("dothing super class") } } class B: A { } extension B { override func doThing() { // error: declarations in extensions cannot override yet print("dothing sub class") super.doThing() } } 

En su ejemplo, parece que el comstackdor le otorga un pase porque A deriva de NSObject, presumiblemente para permitir que esta class interactúe con Objective-C. Esto comstack:

 class A : NSObject { func doThing() { print("dothing super class") } } class B: A { } extension B { override func doThing() { print("dothing sub class") super.doThing() } } 

Mi conjetura es que el hecho de que se le permita hacer esta anulación en absoluto es posiblemente un error. Los docs dicen:

Las extensiones pueden agregar nuevas funcionalidades a un tipo, pero no pueden anular la funcionalidad existente.

Y anular está en ninguna parte en la list como una de las cosas que una extensión puede hacer. Entonces, parece que esto no debería comstackrse. Sin embargo, tal vez esto está permitido deliberadamente para la compatibilidad con Objective-C, como dije antes. De cualquier manera, estamos explorando un caso de borde, y has obtenido muy bien su nerviosismo.

En particular, el código anterior aún no hace que el despacho dynamic entre en funcionamiento. Es por eso que tiene que declarar doThing como dynamic , como lo sugiere @jtbandes, o ponerlo en la class real en lugar de la extensión, si desea que el polymorphism funcione. Por lo tanto, esto funciona de la forma esperada:

 class A : NSObject { dynamic func doThing() { print("dothing super class") } } class B: A { } extension B { override func doThing() { print("dothing sub class") super.doThing() } } 

Y también lo hace esto:

 class A : NSObject { func doThing() { print("dothing super class") } } class B: A { override func doThing() { print("dothing sub class") super.doThing() } } 

Mi conclusión sería: muy buen ejemplo; envíelo a Apple como posible error; y no hagas eso Haga su anulación en la class, no en la extensión.