protocol extension constructors inheritance abstract-class swift

inheritance - extension - swift 4 protocol



Funciones abstractas en Swift Language (11)

Bueno, sé que llego tarde al juego y que podría aprovechar los cambios que han sucedido. Lo siento por eso.

En cualquier caso, me gustaría contribuir con mi respuesta, porque me encanta hacer pruebas y las soluciones con fatalError() son, AFAIK, no comprobables y las que tienen excepciones son mucho más difíciles de probar.

Sugeriría usar un enfoque más ágil . Su objetivo es definir una abstracción que tenga algunos detalles comunes, pero que no esté completamente definida, es decir, los métodos abstractos. Use un protocolo que defina todos los métodos esperados en la abstracción, tanto los definidos como los que no. A continuación, cree una extensión de protocolo que implemente los métodos que se definen en su caso. Finalmente, cualquier clase derivada debe implementar el protocolo, lo que significa todos los métodos, pero los que forman parte de la extensión de protocolo ya tienen su implementación.

Extendiendo su ejemplo con una función concreta:

protocol BaseAbstraction { func abstractFunction() { // How do I force this function to be overridden? } } extension BaseAbstraction { func definedFunction() { print("Hello") } class SubClass : BaseAbstraction { func abstractFunction() { // No need to "Override". Just implement. } }

Tenga en cuenta que al hacer esto, el compilador vuelve a ser su amigo. Si el método no se "reemplaza", obtendrá un error en tiempo de compilación, en lugar de los que obtendría con fatalError() o excepciones que ocurrirían en tiempo de ejecución.

Me gustaría crear una función abstracta en un lenguaje rápido. ¿Es posible?

class BaseClass { func abstractFunction() { // How do I force this function to be overridden? } } class SubClass : BaseClass { override func abstractFunction() { // Override } }


Comprendo la pregunta y estaba buscando la misma solución. Los protocolos no son lo mismo que los métodos abstractos.

En un protocolo, debe especificar que su clase cumple con dicho protocolo, un método abstracto significa que debe anular dicho método.

En otras palabras, los protocolos son tipo de opciones, necesita especificar la clase base y el protocolo, si no especifica el protocolo, entonces no tiene que anular dichos métodos.

Un método abstracto significa que quiere una clase base pero necesita implementar su propio método o dos, que no es lo mismo.

Necesito el mismo comportamiento, es por eso que estaba buscando una solución. Supongo que a Swift le falta esa característica.


Entiendo lo que estás haciendo ahora, creo que sería mejor usar un protocolo

protocol BaseProtocol { func abstractFunction() }

Entonces, solo te conformas con el protocolo:

class SubClass : BaseProtocol { func abstractFunction() { // Override println("Override") } }

Si su clase también es una subclase, los protocolos siguen a la Superclase:

class SubClass: SuperClass, ProtocolOne, ProtocolTwo {}


Esta parece ser la forma "oficial" de cómo Apple está manejando métodos abstractos en UIKit. Eche un vistazo a UITableViewController y la forma en que funciona con UITableViewDelegate . Una de las primeras cosas que haces es agregar una línea: delegate = self . Bueno, ese es exactamente el truco.

1. Pon el método abstracto en un protocolo

protocol AbstractMethodsForClassX { func abstractMethod() -> String } 2. Escribe tu clase base

/// It takes an implementation of the protocol as property (same like the delegate in UITableViewController does) /// And does not implement the protocol as it does not implement the abstract methods. It has the abstract methods available in the `delegate` class BaseClassX { var delegate: AbstractMethodsForClassX! func doSomethingWithAbstractMethod() -> String { return delegate.abstractMethod() + " - And I believe it" } } 3. Escribe la (s) subclase (s).

/// First and only additional thing you have to do, you must set the "delegate" property class ClassX: BaseClassX, AbstractMethodsForClassX { override init() { super.init() delegate = self } func abstractMethod() -> String {return "Yes, this works!"} } Aquí está, cómo usar todo eso

let x = ClassX() x.doSomethingWithAbstractMethod()

Verifique con Playground para ver la salida.

Algunas observaciones

  • Primero, ya se dieron muchas respuestas. Espero que alguien encuentre todo el camino hasta aquí.
  • La pregunta en realidad era encontrar un patrón que implemente:
    • Una clase llama a un método, que debe implementarse en una de sus subclases derivadas (reemplazado)
    • En el mejor de los casos, si el método no se reemplaza en la subclase, obtenga un error durante el tiempo de compilación
  • Lo que pasa con los métodos abstractos es que son una mezcla de una definición de interfaz y parte de una implementación real en la clase base. Los dos al mismo tiempo. Como swift es muy nuevo y está muy definido, no tiene esa convieniencia, sino conceptos "sucios" (aún).
  • Para mí (un pobre chico de Java), este problema evoluciona de vez en cuando. He leído todas las respuestas en esta publicación y esta vez creo que encontré un patrón que parece factible, al menos para mí.
  • Actualización : parece que los implementadores de UIKit en Apple usan el mismo patrón. UITableViewController implementa UITableViewDelegate pero aún necesita ser registros como delegado configurando explícitamente la propiedad de delegate .
  • Todo esto se prueba en Playground of Xcode 7.3.1

Hay otra alternativa a este problema, aunque todavía hay una desventaja en comparación con la propuesta de @ jaumard; requiere una declaración de devolución. Aunque echo de menos el punto de necesitarlo, porque consiste en lanzar directamente una excepción:

class AbstractMethodException : NSException { init() { super.init( name: "Called an abstract method", reason: "All abstract methods must be overriden by subclasses", userInfo: nil ); } }

Y entonces:

class BaseClass { func abstractFunction() { AbstractMethodException.raise(); } }

Lo que sea que venga después es inalcanzable, así que no veo por qué forzar el regreso.


Lo que quieres no es una clase base, sino un protocolo.

protocol MyProtocol { func abstractFunction() } class MyClass : MyProtocol { func abstractFunction() { } }

Si no proporciona abstractFunction en su clase, es un error.

Si aún necesita la clase base para otro comportamiento, puede hacer esto:

class MyClass : BaseClass, MyProtocol { func abstractFunction() { } }


No hay concepto de resumen en Swift (como Objective-C) pero puedes hacer esto:

class BaseClass { func abstractFunction() { preconditionFailure("This method must be overridden") } } class SubClass : BaseClass { override func abstractFunction() { // Override } }


No sé si va a ser útil, pero tuve un problema similar con el método abstracto al intentar crear el juego SpritKit. Lo que quería es una clase abstracta de Animal que tenga métodos tales como move (), run (), etc., pero los nombres de los sprites (y otras funcionalidades) deberían ser proporcionados por los niños de la clase. Así que terminé haciendo algo como esto (probado para Swift 2):

import SpriteKit // --- Functions that must be implemented by child of Animal public protocol InheritedAnimal { func walkSpriteNames() -> [String] func runSpriteNames() -> [String] } // --- Abstract animal public class Animal: SKNode { private let inheritedAnimal: InheritedAnimal public init(inheritedAnimal: InheritedAnimal) { self.inheritedAnimal = inheritedAnimal super.init() } public required init?(coder aDecoder: NSCoder) { fatalError("NSCoding not supported") } public func walk() { let sprites = inheritedAnimal.walkSpriteNames() // create animation with walking sprites... } public func run() { let sprites = inheritedAnimal.runSpriteNames() // create animation with running sprites } } // --- Sheep public class SheepAnimal: Animal { public required init?(coder aDecoder: NSCoder) { fatalError("NSCoding not supported") } public required init() { super.init(inheritedAnimal: InheritedAnimalImpl()) } private class InheritedAnimalImpl: InheritedAnimal { init() {} func walkSpriteNames() -> [String] { return ["sheep_step_01", "sheep_step_02", "sheep_step_03", "sheep_step_04"] } func runSpriteNames() -> [String] { return ["sheep_run_01", "sheep_run_02"] } } }


Transfiero una cantidad considerable de código desde una plataforma que admite clases base abstractas a Swift y me dedico a esto mucho. Si lo que realmente quiere es la funcionalidad de una clase base abstracta, eso significa que esta clase sirve tanto como una implementación de la funcionalidad de clase compartida compartida (de lo contrario, sería solo una interfaz / protocolo) Y define los métodos que deben ser implementados por clases derivadas

Para hacer eso en Swift, necesitarás un protocolo y una clase base.

protocol Thing { func sharedFunction() func abstractFunction() } class BaseThing { func sharedFunction() { println("All classes share this implementation") } }

Tenga en cuenta que la clase base implementa los métodos compartidos, pero no implementa el protocolo (ya que no implementa todos los métodos).

Luego en la clase derivada:

class DerivedThing : BaseThing, Thing { func abstractFunction() { println("Derived classes implement this"); } }

La clase derivada hereda sharedFunction de la clase base, ayudándole a satisfacer esa parte del protocolo, y el protocolo aún requiere que la clase derivada implemente abstractFunction.

El único inconveniente real de este método es que, dado que la clase base no implementa el protocolo, si tiene un método de clase base que necesita acceso a una propiedad / método de protocolo, tendrá que anularlo en la clase derivada, y desde allí llamar la clase base (a través de super) que pasa a self modo que la clase base tiene una instancia del protocolo con el que hacer su trabajo.

Por ejemplo, digamos que sharedFunction necesitaba llamar a abstractFunction. El protocolo permanecería igual y las clases ahora se verían así:

class BaseThing { func sharedFunction(thing: Thing) { println("All classes share this implementation") thing.abstractFunction() } } class DerivedThing : BaseThing, Thing { func sharedFunction() { super.sharedFunction(self) } func abstractFunction() { println("Derived classes implement this"); } }

Ahora la función shared de la clase derivada satisface esa parte del protocolo, pero la clase derivada aún puede compartir la lógica de la clase base de una manera razonablemente sencilla.


Una forma de hacerlo es usar un cierre opcional definido en la clase base, y los niños pueden optar por implementarlo o no.

class BaseClass { var abstractClosure?:(()->())? func someFunc() { if let abstractClosure=abstractClosure { abstractClosure() } } } class SubClass : BaseClass { init() { super.init() abstractClosure={ ..... } } }


Usar la palabra clave assert para aplicar métodos abstractos:

class Abstract { func doWork() { assert(false, "This method must be overriden by the subclass") } } class Concrete : Abstract { override func doWork() { println("Did some work!") } } let abstract = Abstract() let concrete = Concrete() abstract.doWork() // fails concrete.doWork() // OK

Sin embargo, como Steve Waddicor mencionó, probablemente prefiera un protocol .