Ich möchte eine abstrakte Funktion in schneller Sprache erstellen. Ist es möglich?
class BaseClass {
func abstractFunction() {
// How do I force this function to be overridden?
}
}
class SubClass : BaseClass {
override func abstractFunction() {
// Override
}
}
Antworten:
In Swift gibt es kein abstraktes Konzept (wie Objective-C), aber Sie können dies tun:
quelle
assert(false, "This method must be overriden by the subclass")
.fatalError("This method must be overridden")
preconditionFailure("Bla bla bla")
in Swift, das in Release-Builds ausgeführt wird und die Notwendigkeit einer return-Anweisung beseitigt. EDIT: Nur fand heraus , dass diese Methode im Grunde gleich ist ,fatalError()
aber es ist der richtige Weg , mehr (Bessere Dokumentation, in Swift eingeführt zusammen mitprecondition()
,assert()
undassertionFailure()
, lesen Sie hier )Was Sie wollen, ist keine Basisklasse, sondern ein Protokoll.
Wenn Sie in Ihrer Klasse keine abstractFunction angeben, liegt ein Fehler vor.
Wenn Sie die Basisklasse für ein anderes Verhalten noch benötigen, können Sie Folgendes tun:
quelle
Ich portiere eine ganze Menge Code von einer Plattform, die abstrakte Basisklassen unterstützt, nach Swift und laufe viel darauf ein. Wenn Sie wirklich die Funktionalität einer abstrakten Basisklasse wünschen, bedeutet dies, dass diese Klasse sowohl als Implementierung einer gemeinsam genutzten basierten Klassenfunktionalität dient (andernfalls wäre es nur eine Schnittstelle / ein Protokoll), als auch Methoden definiert, die von implementiert werden müssen abgeleitete Klassen.
Dazu benötigen Sie in Swift ein Protokoll und eine Basisklasse.
Beachten Sie, dass die Basisklasse die gemeinsam genutzten Methoden implementiert, das Protokoll jedoch nicht implementiert (da nicht alle Methoden implementiert werden).
Dann in der abgeleiteten Klasse:
Die abgeleitete Klasse erbt sharedFunction von der Basisklasse, wodurch dieser Teil des Protokolls erfüllt wird, und das Protokoll erfordert weiterhin, dass die abgeleitete Klasse abstractFunction implementiert.
Der einzige wirkliche Nachteil dieser Methode besteht darin, dass Sie, da die Basisklasse das Protokoll nicht implementiert, eine Basisklassenmethode, die Zugriff auf eine Protokolleigenschaft / -methode benötigt, diese in der abgeleiteten Klasse überschreiben und von dort aus aufrufen müssen Die Basisklasse (über Super) wird übergeben,
self
sodass die Basisklasse eine Instanz des Protokolls hat, mit dem sie ihre Arbeit erledigen kann.Angenommen, sharedFunction muss abstraktFunction aufrufen. Das Protokoll würde gleich bleiben und die Klassen würden nun so aussehen:
Jetzt erfüllt die sharedFunction aus der abgeleiteten Klasse diesen Teil des Protokolls, aber die abgeleitete Klasse kann die Basisklassenlogik immer noch auf einigermaßen einfache Weise gemeinsam nutzen.
quelle
Dies scheint die "offizielle" Art zu sein, wie Apple mit abstrakten Methoden in UIKit umgeht. Schauen Sie sich an
1. Fügen Sie die abstrakte Methode in ein Protokoll ein 2. Schreiben Sie Ihre Basisklasse 3. Schreiben Sie die Unterklasse (n). Hier erfahren Sie, wie Sie all das nutzen könnenUITableViewController
und wie es funktioniertUITableViewDelegate
. Eines der allerersten Dinge, die Sie tun, ist das Hinzufügen einer Zeile :delegate = self
. Das ist genau der Trick.Wenden Sie sich an Playground, um die Ausgabe zu sehen.
Einige Bemerkungen
UITableViewController
implementiertUITableViewDelegate
, muss aber weiterhin als Delegat registriert werden, indem diedelegate
Eigenschaft explizit festgelegt wird .quelle
getComments
Methode für den übergeordneten Delegaten. Es gibt eine Handvoll Kommentartypen, und ich möchte diejenigen, die für jedes Objekt relevant sind. Ich möchte also, dass die Unterklassen nicht kompiliert werden, wenn ich diesedelegate.getComments()
Methode nicht überschreibe. Der VC weiß nur, dass er einParentDelegate
Objekt namensdelegate
oderBaseClassX
in Ihrem Beispiel hat, hat aberBaseClassX
nicht die abstrahierte Methode. Ich würde den VC brauchen, um genau zu wissen, dass er den verwendetSubclassedDelegate
.Eine Möglichkeit, dies zu tun, besteht darin, einen optionalen Abschluss zu verwenden, der in der Basisklasse definiert ist, und die Kinder können wählen, ob er implementiert werden soll oder nicht.
quelle
Nun, ich weiß, dass ich zu spät zum Spiel komme und dass ich möglicherweise die Änderungen ausnutzen werde, die stattgefunden haben. Das tut mir leid.
Auf jeden Fall möchte ich meine Antwort einbringen, weil ich es liebe zu testen und die Lösungen mit
fatalError()
AFAIK nicht testbar sind und diejenigen mit Ausnahmen viel schwieriger zu testen sind.Ich würde vorschlagen, einen schnelleren Ansatz zu verwenden. Ihr Ziel ist es, eine Abstraktion zu definieren, die einige gemeinsame Details aufweist, die jedoch nicht vollständig definiert ist, dh die abstrakte (n) Methode (n). Verwenden Sie ein Protokoll, das alle erwarteten Methoden in der Abstraktion definiert, sowohl die definierten als auch die nicht definierten. Erstellen Sie dann eine Protokollerweiterung, die die in Ihrem Fall definierten Methoden implementiert. Schließlich muss jede abgeleitete Klasse das Protokoll implementieren, dh alle Methoden, aber diejenigen, die Teil der Protokollerweiterung sind, haben bereits ihre Implementierung.
Erweitern Sie Ihr Beispiel um eine konkrete Funktion:
Beachten Sie, dass der Compiler auf diese Weise wieder Ihr Freund ist. Wenn die Methode nicht "überschrieben" wird, wird beim Kompilieren ein Fehler angezeigt, anstatt derjenigen, die Sie erhalten würden,
fatalError()
oder Ausnahmen, die zur Laufzeit auftreten würden.quelle
Ich verstehe, was Sie jetzt tun. Ich denke, Sie sollten ein Protokoll besser verwenden
Dann passen Sie sich einfach dem Protokoll an:
Wenn Ihre Klasse auch eine Unterklasse ist, folgen die Protokolle der Oberklasse:
quelle
Verwenden von
assert
Schlüsselwörtern zum Erzwingen abstrakter Methoden:Wie Steve Waddicor bereits erwähnte, möchten Sie wahrscheinlich
protocol
stattdessen eine.quelle
Ich verstehe die Frage und suchte nach der gleichen Lösung. Protokolle sind nicht dasselbe wie abstrakte Methoden.
In einem Protokoll müssen Sie angeben, dass Ihre Klasse einem solchen Protokoll entspricht. Eine abstrakte Methode bedeutet, dass Sie diese Methode überschreiben müssen.
Mit anderen Worten, Protokolle sind eine Art Option. Sie müssen die Basisklasse und das Protokoll angeben. Wenn Sie das Protokoll nicht angeben, müssen Sie solche Methoden nicht überschreiben.
Eine abstrakte Methode bedeutet, dass Sie eine Basisklasse möchten, aber Ihre oder zwei eigene Methoden implementieren müssen, was nicht dasselbe ist.
Ich brauche das gleiche Verhalten, deshalb habe ich nach einer Lösung gesucht. Ich denke, Swift fehlt eine solche Funktion.
quelle
Es gibt eine andere Alternative zu diesem Problem, obwohl es im Vergleich zu @ jaumards Vorschlag immer noch einen Nachteil gibt. Es erfordert eine return-Anweisung. Obwohl ich den Punkt vermisse, es zu verlangen, weil es darin besteht, eine Ausnahme direkt auszulösen:
Und dann:
Was auch immer danach kommt, ist nicht erreichbar, deshalb verstehe ich nicht, warum ich die Rückkehr erzwinge.
quelle
AbstractMethodException().raise()
?Ich weiß nicht, ob es nützlich sein wird, aber ich hatte ein ähnliches Problem mit der abstrahierten Methode, als ich versuchte, ein SpritKit-Spiel zu erstellen. Was ich wollte, ist eine abstrakte Tierklasse, die Methoden wie move (), run () usw. enthält, aber Sprite-Namen (und andere Funktionen) sollten von Klassenkindern bereitgestellt werden. Also habe ich so etwas gemacht (getestet für Swift 2):
quelle