inheritance abstract-class subclass swift

inheritance - Clases abstractas en Swift Language



abstract-class subclass (8)

Creo que este es el más cercano al abstract de Java o al abstract C #:

class AbstractClass { private init() { } }

Tenga en cuenta que, para que los modificadores private funcionen, debe definir esta clase en un archivo Swift diferente.

EDITAR: Aún así, este código no permite declarar un método abstracto y así forzar su implementación.

¿Hay alguna manera de crear una clase abstracta en Swift Language, o es una limitación como Objective-C? Me gustaría crear una clase abstracta comparable a lo que Java define como una clase abstracta.


Después de luchar durante varias semanas, finalmente me di cuenta de cómo traducir una clase abstracta de Java / PHP a Swift:

public class AbstractClass: NSObject { internal override init(){} public func getFoodToEat()->String { if(self._iAmHungry()) { return self._myFavoriteFood(); }else{ return ""; } } private func _myFavoriteFood()->String { return "Sandwich"; } internal func _iAmHungry()->Bool { fatalError(__FUNCTION__ + "Must be overridden"); return false; } } public class ConcreteClass: AbstractClass, IConcreteClass { private var _hungry: Bool = false; public override init() { super.init(); } public func starve()->Void { self._hungry = true; } public override func _iAmHungry()->Bool { return self._hungry; } } public protocol IConcreteClass { func _iAmHungry()->Bool; } class ConcreteClassTest: XCTestCase { func testExample() { var concreteClass: ConcreteClass = ConcreteClass(); XCTAssertEqual("", concreteClass.getFoodToEat()); concreteClass.starve(); XCTAssertEqual("Sandwich", concreteClass.getFoodToEat()); } }

Sin embargo, creo que Apple no implementó clases abstractas porque generalmente usa el patrón delegado + protocolo. Por ejemplo, el mismo patrón anterior se haría mejor de esta manera:

import UIKit public class GoldenSpoonChild { private var delegate: IStomach!; internal init(){} internal func setup(delegate: IStomach) { self.delegate = delegate; } public func getFoodToEat()->String { if(self.delegate.iAmHungry()) { return self._myFavoriteFood(); }else{ return ""; } } private func _myFavoriteFood()->String { return "Sandwich"; } } public class Mother: GoldenSpoonChild, IStomach { private var _hungry: Bool = false; public override init() { super.init(); super.setup(self); } public func makeFamilyHungry()->Void { self._hungry = true; } public func iAmHungry()->Bool { return self._hungry; } } protocol IStomach { func iAmHungry()->Bool; } class DelegateTest: XCTestCase { func testGetFood() { var concreteClass: Mother = Mother(); XCTAssertEqual("", concreteClass.getFoodToEat()); concreteClass.makeFamilyHungry(); XCTAssertEqual("Sandwich", concreteClass.getFoodToEat()); } }

Necesitaba este tipo de patrón porque quería utilizar algunos métodos en UITableViewController, como viewWillAppear, etc. ¿Fue útil?


Hay una forma de simular clases abstractas usando Protocolos. Esto es un ejemplo:

protocol MyProtocol { func doIt() } class BaseClass { var myDelegate: MyProtocol! init() { ... } func myFunc() { ... self.myDelegate.doIt() ... } } class ChildClass: BaseClass, MyProtocol { override init(){ super.init() self.myDelegate = self } func doIt() { // Custom implementation } }


Intentaba crear una clase abstracta de Weather , pero el uso de protocolos no era ideal, ya que tenía que escribir los mismos métodos de init una y otra vez. Extendí el protocolo y escribí un método init con sus problemas, especialmente porque estaba usando NSObject conforme a NSCoding .

Así que se me ocurrió esto para la conformidad de NSCoding :

required init?(coder aDecoder: NSCoder) { guard type(of: self) != Weather.self else { fatalError("<Weather> This is an abstract class. Use a subclass of `Weather`.") } // Initialize... }

En cuanto a init :

fileprivate init(param: Any...) { // Initialize }


La forma más simple es usar una llamada a fatalError("Not Implemented") en el método abstracto (no variable) en la extensión del protocolo.

protocol MyInterface { func myMethod() -> String } extension MyInterface { func myMethod() -> String { fatalError("Not Implemented") } } class MyConcreteClass: MyInterface { func myMethod() -> String { return "The output" } } MyConcreteClass().myMethod()


No hay clases abstractas en Swift (al igual que Objective-C). Su mejor opción será usar un Protocol , que es como una interfaz Java.

Con Swift 2.0, puede agregar implementaciones de métodos e implementaciones de propiedades calculadas mediante extensiones de protocolo. Sus únicas restricciones son que no puede proporcionar variables o constantes de miembro y no hay despacho dinámico .

Un ejemplo de esta técnica sería:

protocol Employee { var annualSalary: Int {get} } extension Employee { var biweeklySalary: Int { return self.annualSalary / 26 } func logSalary() { print("$/(self.annualSalary) per year or $/(self.biweeklySalary) biweekly") } } struct SoftwareEngineer: Employee { var annualSalary: Int func logSalary() { print("overridden") } } let sarah = SoftwareEngineer(annualSalary: 100000) sarah.logSalary() // prints: overridden (sarah as Employee).logSalary() // prints: $100000 per year or $3846 biweekly

Tenga en cuenta que esto proporciona funciones similares a la "clase abstracta" incluso para las estructuras, pero las clases también pueden implementar el mismo protocolo.

También tenga en cuenta que cada clase o estructura que implementa el protocolo de Empleado tendrá que declarar nuevamente la propiedad anual de Salario.

Lo más importante es darse cuenta de que no hay un despacho dinámico . Cuando se llama a logSalary en la instancia que está almacenada como un SoftwareEngineer , llama a la versión anulada del método. Cuando se llama a logSalary en la instancia una vez que se ha enviado a un Employee , llama a la implementación original (no se distribuye dinámicamente a la versión reemplazada aunque la instancia sea en realidad un Software Engineer .

Para obtener más información, consulte el excelente video de WWDC sobre esta característica: Creación de mejores aplicaciones con tipos de valores en Swift


Una forma más de cómo puede implementar la clase abstracta es bloquear el inicializador. Lo hice de esta manera:

class Element:CALayer { // IT''S ABSTRACT CLASS override init(){ super.init() if self.dynamicType === Element.self { fatalError("Element is abstract class, do not try to create instance of this class") } } }


Tenga en cuenta que esta respuesta está dirigida a Swift 2.0 y superior

Puede lograr el mismo comportamiento con protocolos y extensiones de protocolo.

Primero, escribe un protocolo que actúa como interfaz para todos los métodos que deben implementarse en todos los tipos que se ajustan a él.

protocol Drivable { var speed: Float { get set } }

Luego puede agregar un comportamiento predeterminado a todos los tipos que se ajusten a él

extension Drivable { func accelerate(by: Float) { speed += by } }

Ahora puede crear nuevos tipos implementando Drivable .

struct Car: Drivable { var speed: Float = 0.0 init() {} } let c = Car() c.accelerate(10)

Entonces, básicamente, obtienes:

  1. Realice comprobaciones de tiempo que garanticen que todos los Drivable s implementen la speed
  2. Puede implementar el comportamiento predeterminado para todos los tipos que se ajusten a Drivable ( accelerate )
  3. Drivable está garantizado para no ser instanciado ya que es solo un protocolo

Este modelo realmente se comporta mucho más como rasgos, lo que significa que puede ajustarse a múltiples protocolos y asumir implementaciones predeterminadas de cualquiera de ellos, mientras que con una superclase abstracta está limitado a una jerarquía de clases simple.