type protocol generic extension example delegate associated and inheritance swift interface protocols typechecking

inheritance - generic - Swift: requiere que las clases que implementan el protocolo sean subclases de una cierta clase



swift generics (8)

A partir de Swift 4 ahora puede definir esto como sigue:

let myView: NSView & TransmogrifiableView

Para obtener más información, consulte el número de pregunta 156: Subventabilidad de las clases especiales

Estoy creando varias clases NSView , todas las cuales soportan una operación especial, que llamaremos transmogrify . A primera vista, este parece ser el lugar perfecto para un protocolo:

protocol TransmogrifiableView { func transmogrify() }

Sin embargo, este protocolo no NSView que cada TransmogrifiableView sea ​​también un NSView . Esto significa que los métodos NSView que NSView en un TransmogrifiableView no incluirán verificación:

let myView: TransmogrifiableView = getTransmogrifiableView() let theSuperView = myView.superView // error: TransmogrifiableView does not have a property called ''superview''

No sé cómo exigir que todas las clases que implementan mi protocolo también sean subclases de NSView . Intenté esto:

protocol TransmogrifiableView: NSView { func transmogrify() }

pero Swift se queja de que los protocolos no pueden heredar de las clases. No ayuda a convertir el protocolo en un protocolo de solo clase utilizando

protocol TransmogrifiableView: class, NSView { func transmogrify() }

No puedo hacer que TransmogrifiableView una superclase en lugar de un protocolo, porque algunas de mis clases TransmogrifiableView deben ser subclases de otras vistas no transmocrificables.

¿Cómo debo exigir que todos los NSView también sean NSView ? Realmente no quiero salpicar mi código con conversiones " as ", que son malas formas y que distraen.


Creo que buscas una subclase de NSView . Prueba esto:

protocol TransmogrifiableView { func transmogrify() } class MyNSView: NSView, TransmogrifiableView { // do stuff. }

Y más tarde en el código acepta objetos de tipo MyNSView .

Editar

Quizás quieras una Extension , mira this

extension NSView: TransmogrifiableView { // implementation of protocol requirements goes here }

  • Tenga en cuenta que no podrá obtener un NSView sin este método adicional.
  • Puede ampliar por separado las subclases de NSView para anular este nuevo método.

Otra opción más es crear una clase que contenga un puntero a un NSView e implemente métodos adicionales. Esto también te obligará a utilizar todos los métodos de NSView que quieras usar.

class NSViewWrapper: TransmogrifiableView { var view : NSView! // init with the view required. // implementation of protocol requirements goes here. ..... // proxy all methods from NSView. func getSuperView(){ return self.view.superView } }

Esto es bastante largo y no agradable, pero funcionará. Le recomendaría que use esto solo si realmente no puede trabajar con extensiones (porque necesita NSViews sin el método adicional).


Hay una solución mediante el uso de tipos asociados para aplicar la subclase:

protocol TransmogrifiableView { associatedtype View: NSView = Self func transmogrify() } class MyView: NSView, TransmogrifiableView { ... } // compiles class MyOtherClass: TransmogrifiableView { ... } // doesn''t compile


Para Swift 4, basado en la aguda percepción de @ Antoine:

Cree un protocolo y luego use una tipografía para dar un nombre más limpio a un tipo que cumpla tanto con una clase como con el protocolo.

protocol Transmogrifiable { func transmogrify() } typealias TransmogrifiableView = NSView & Transmogrifiable

A continuación, puede definir una clase que hereda de ese tipo ....

class ATransmogView: TransmogrifiableView { func transmogrify() { print("I''m transmogging") } }

.... o define una clase que hereda del protocolo y una subclase

// this also qualifies as a TransmogrifiableView class BTransmogView: NSTextView, Transmogrifiable { func transmogrify() { print("I''m transmogging too") } }

Ahora puedes hacer esto.

func getTransmogrifiableView() -> TransmogrifiableView { return someBool ? ATransmogView() : BTransmogView() }

Y esto ahora compila.

let myView: TransmogrifiableView = getTransmogrifiableView() let theSuperView = myView.superView


Podrías usar algo como esto:

protocol TransmogrifiableView where Self:NSView {}

Esto requiere que todas las instancias creadas se ajusten al protocolo TransmogrifiableView para ser subclassed con NSView


Según la definición, un protocolo solo declara los requisitos de "métodos, propiedades y otros requisitos ". Y por "otros requisitos" significa que una superclase no forma parte de ella.

Un protocolo define un modelo de métodos, propiedades y otros requisitos que se adaptan a una tarea o pieza de funcionalidad en particular.

En este momento, no veo una solución limpia. Es posible usar una cláusula where para definir un tipo que sea NSView y que se ajuste a NSView de la siguiente manera:

class MyClass<T where T: NSView, T: TransmogrifiableView> { var aTransmogrifiableNSView: T }

O podrías usar otra superclase:

protocol TransmogrifiableViewProtocol { func transmogrify() } class TransmogrifiableView: NSView, TransmogrifiableViewProtocol { func transmogrify() { assert(false, "transmogrify() must be overwritten!") } } class AnImplementedTransmogrifiableView: TransmogrifiableView { func transmogrify() { println("Do the transmogrification...") } }

Al final, ambas soluciones no son limpias y no me satisfarán. ¿Tal vez una palabra clave abstract se agregará a Swift algún día?


Todavía no es la solución ideal, pero aquí hay un patrón que uso en ocasiones:

  1. Defina un protocolo con los métodos que desea aplicar.
  2. Defina su clase base, implementando lo que quiera que los niños obtengan gratis.
  3. En esa clase base (desde el n. ° 2), tenga una variable "delegada" opcional del protocolo que hizo en el n. ° 1.
  4. Defina todas las clases secundarias para que hereden la clase base e implementen el protocolo.

Esto permite que su clase base invoque los métodos de protocolo mientras obliga a los niños a implementarlos (por ejemplo, self.myDelegate? .myProtocolMethod).


compruebe esta solución aquí ... Swift - método de clase que debe ser anulado por subclase

Esta solución permite heredar de una clase y también tener la verificación del tiempo de compilación del protocolo. :)