Gibt es eine Möglichkeit, eine abstrakte Klasse in der Swift-Sprache zu erstellen, oder ist dies eine Einschränkung wie bei Objective-C? Ich möchte eine abstrakte Klasse erstellen, die mit dem vergleichbar ist, was Java als abstrakte Klasse definiert.
140
Antworten:
In Swift gibt es keine abstrakten Klassen (genau wie in Objective-C). Am besten verwenden Sie ein Protokoll , das einer Java-Schnittstelle ähnelt.
Mit Swift 2.0 können Sie dann Methodenimplementierungen und berechnete Eigenschaftsimplementierungen mithilfe von Protokollerweiterungen hinzufügen. Ihre einzigen Einschränkungen bestehen darin, dass Sie keine Mitgliedsvariablen oder Konstanten bereitstellen können und kein dynamischer Versand erfolgt .
Ein Beispiel für diese Technik wäre:
Beachten Sie, dass dies auch für Strukturen "abstrakte Klassen" -ähnliche Funktionen bietet, Klassen jedoch auch dasselbe Protokoll implementieren können.
Beachten Sie auch, dass jede Klasse oder Struktur, die das Mitarbeiterprotokoll implementiert, die Eigenschaft annualSalary erneut deklarieren muss.
Beachten Sie vor allem, dass kein dynamischer Versand erfolgt . Wenn
logSalary
für die Instanz aufgerufen wird, die als gespeichert ist, wirdSoftwareEngineer
die überschriebene Version der Methode aufgerufen . WannlogSalary
die Instanz aufgerufen wird, nachdem sie in eine umgewandelt wurdeEmployee
, wird die ursprüngliche Implementierung aufgerufen (sie wird nicht dynamisch an die überschriebene Version gesendet, obwohl die Instanz tatsächlich eine istSoftware Engineer
.Weitere Informationen finden Sie in einem großartigen WWDC-Video zu dieser Funktion: Bessere Apps mit Werttypen in Swift erstellen
quelle
protocol Animal { var property : Int { get set } }
. Sie können das Set auchfunc logSalary()
die Mitarbeiterprotokolldeklaration hinzufügen , wird das Beispieloverridden
für beide Aufrufe an gedrucktlogSalary()
. Dies ist in Swift 3.1. So erhalten Sie die Vorteile des Polymorphismus. In beiden Fällen wird die richtige Methode aufgerufen.Beachten Sie, dass diese Antwort auf Swift 2.0 und höher ausgerichtet ist
Sie können dasselbe Verhalten mit Protokollen und Protokollerweiterungen erzielen.
Zunächst schreiben Sie ein Protokoll, das als Schnittstelle für alle Methoden fungiert, die in allen entsprechenden Typen implementiert werden müssen.
Anschließend können Sie allen entsprechenden Typen ein Standardverhalten hinzufügen
Sie können jetzt neue Typen erstellen, indem Sie implementieren
Drivable
.Im Grunde genommen bekommen Sie also:
Drivable
implementiert werdenspeed
Drivable
(accelerate
) entsprechenDrivable
wird garantiert nicht instanziiert, da es sich nur um ein Protokoll handeltDieses Modell verhält sich tatsächlich viel mehr wie Merkmale, dh Sie können sich an mehrere Protokolle anpassen und Standardimplementierungen von jedem übernehmen, während Sie sich bei einer abstrakten Oberklasse auf eine einfache Klassenhierarchie beschränken.
quelle
UICollectionViewDatasource
. Ich möchte das gesamte Boilerplate entfernen und es in einem separaten Protokoll / einer separaten Erweiterung kapseln und dann von mehreren Klassen wiederverwenden. In der Tat wäre das Vorlagenmuster hier perfekt, aber ...Ich denke, dies ist am nächsten an Java
abstract
oder C #abstract
:Beachten Sie, dass
private
Sie diese Klasse in einer separaten Swift-Datei definieren müssen, damit die Modifikatoren funktionieren.BEARBEITEN: Dieser Code erlaubt es jedoch nicht, eine abstrakte Methode zu deklarieren und somit deren Implementierung zu erzwingen.
quelle
Am einfachsten ist es, einen Aufruf
fatalError("Not Implemented")
der abstrakten Methode (nicht variabel) in der Protokollerweiterung zu verwenden.quelle
(MyConcreteClass() as MyInterface).myMethod()
aber es tut es! Der Schlüssel istmyMethod
in der Protokolldeklaration enthalten. Andernfalls stürzt der Anruf ab.Nachdem ich einige Wochen lang Probleme hatte, wurde mir endlich klar, wie man eine abstrakte Java / PHP-Klasse in Swift übersetzt:
Ich denke jedoch, dass Apple keine abstrakten Klassen implementiert hat, da es im Allgemeinen stattdessen das Delegate + -Protokollmuster verwendet. Zum Beispiel wäre das gleiche Muster oben besser wie folgt:
Ich brauchte diese Art von Muster, weil ich einige Methoden in UITableViewController wie viewWillAppear usw. vereinheitlichen wollte. War dies hilfreich?
quelle
Es gibt eine Möglichkeit, abstrakte Klassen mithilfe von Protokollen zu simulieren. Dies ist ein Beispiel:
quelle
Eine weitere Möglichkeit, eine abstrakte Klasse zu implementieren, besteht darin, den Initialisierer zu blockieren. Ich habe es so gemacht:
quelle
Ich habe versucht, eine
Weather
abstrakte Klasse zu erstellen, aber die Verwendung von Protokollen war nicht ideal, da ichinit
immer wieder dieselben Methoden schreiben musste. Das Erweitern des Protokolls und das Schreiben einerinit
Methode hatte Probleme, insbesondere da ichNSObject
Konformität mit verwendet habeNSCoding
.Also habe ich mir das für die
NSCoding
Konformität ausgedacht:Wie für
init
:quelle
Verschieben Sie alle Verweise auf abstrakte Eigenschaften und Methoden der Basisklasse in die Implementierung der Protokollerweiterung, wobei Self auf die Basisklasse beschränkt ist. Sie erhalten Zugriff auf alle Methoden und Eigenschaften der Basisklasse. Zusätzlich überprüft der Compiler die Implementierung abstrakter Methoden und Eigenschaften im Protokoll für abgeleitete Klassen
quelle
Mit der Einschränkung, dass kein dynamischer Versand erfolgt, können Sie Folgendes tun:
quelle