Kann jemand in Swift erklären, wie eine Eigenschaft einer Oberklasse mit einem anderen Objekt überschrieben wird, das von der ursprünglichen Eigenschaft untergeordnet ist?
Nehmen Sie dieses einfache Beispiel:
class Chassis {}
class RacingChassis : Chassis {}
class Car {
let chassis = Chassis()
}
class RaceCar: Car {
override let chassis = RacingChassis() //Error here
}
Dies gibt den Fehler:
Cannot override with a stored property 'chassis'
Wenn ich stattdessen ein Chassis als 'var' habe, wird folgende Fehlermeldung angezeigt:
Cannot override mutable property 'chassis' of type 'Chassis' with covariant type 'RacingChassis'
Das einzige, was ich in der Anleitung unter "Überschreiben von Eigenschaften" finden konnte, ist, dass wir den Getter und den Setter überschreiben müssen, was möglicherweise zum Ändern des Werts der Eigenschaft (wenn es 'var' ist) funktioniert, aber was ist mit dem Ändern der Eigenschaftsklasse ?
strong
Eigenschaft ist und beim Versuch, sie zu überschreiben, ein Fehler aufgetreten ist. Es scheint jedoch, dass ich übersehen habe, dass dies zu einem "implizit ausgepackten optionalen" (chassis!
) in führt Schnell, alsooverride var chassis : Chassis!
behebt es.Das scheint zu funktionieren
quelle
let
in derCar
Klasse definiert ist, was eine Änderung unmöglich macht. Wir können nur diechassis
Eigenschaft derRaceCar
Klasse ändern .Versuche dies:
Dann:
Details unter http://www.mylonly.com/14957025459875.html
quelle
Der bereitgestellte Solution Dash funktioniert gut, außer dass die Superklasse mit dem Schlüsselwort let und nicht mit var deklariert werden muss. Hier ist eine Lösung, die möglich, aber NICHT EMPFOHLEN ist!
Die folgende Lösung wird mit Xcode 6.2, SWIFT 1.1 kompiliert (wenn sich alle Klassen in unterschiedlichen Swift-Dateien befinden), sollte jedoch vermieden werden, da dies zu unerwartetem Verhalten führen kann (einschließlich eines Absturzes, insbesondere bei Verwendung nicht optionaler Typen). HINWEIS: DIESES FUNKTIONIERT NICHT MIT XCODE 6.3 BETA 3, SWIFT 1.2
quelle
Theoretisch darfst du das so machen ...
Dies funktioniert perfekt auf einem Xcode-Spielplatz.
Aber , wenn Sie versuchen , dies in einem realen Projekt, ein Compiler - Fehler sagt Ihnen:
Ich habe bisher nur Xcode 6.0 GM überprüft.
Leider müssen Sie warten, bis Apple dies behebt.
Ich habe auch einen Fehlerbericht eingereicht. 18518795
quelle
Ich habe viele Gründe gesehen, warum das Entwerfen einer API mithilfe von Variablen anstelle von Funktionen problematisch ist und sich für mich wie eine Problemumgehung anfühlt, wenn ich berechnete Eigenschaften verwende. Es gibt gute Gründe, Ihre Instanzvariablen gekapselt zu halten. Hier habe ich ein Protokoll Automobile erstellt, dem Car entspricht. Dieses Protokoll verfügt über eine Zugriffsmethode, die ein Chassis-Objekt zurückgibt. Da das Auto dem entspricht, kann die RaceCar-Unterklasse es überschreiben und eine andere Chassis-Unterklasse zurückgeben. Dadurch kann die Car-Klasse auf eine Schnittstelle (Automobile) programmieren, und die RaceCar-Klasse, die sich mit RacingChassis auskennt, kann direkt auf die Variable _racingChassis zugreifen.
Ein weiteres Beispiel dafür, warum das Entwerfen einer API mithilfe von Variablen nicht funktioniert, ist, wenn Sie Variablen in einem Protokoll haben. Wenn Sie alle Protokollfunktionen in Erweiterungen aufteilen möchten, können Sie dies tun, außer dass gespeicherte Eigenschaften nicht in Erweiterungen platziert werden können und in der Klasse definiert werden müssen (damit diese kompiliert werden können, müssen Sie den Code auskommentieren AdaptableViewController-Klasse und entfernen Sie die Modusvariable aus der Erweiterung):
Der obige Code hat den folgenden Compilerfehler: "Erweiterungen haben möglicherweise keine gespeicherten Eigenschaften". So können Sie das obige Beispiel neu schreiben, damit alles im Protokoll in der Erweiterung getrennt werden kann, indem Sie stattdessen Funktionen verwenden:
quelle
Sie können es mit Generika erreichen:
Mit diesem Ansatz erhalten Sie 100% sicheren Code ohne erzwungenes Auspacken.
Aber dass dies eine Art Hack ist und wenn Sie mehrere Eigenschaften neu definieren müssen, dann sehen Ihre Klassendeklarationen wie ein totales Chaos aus. Seien Sie also vorsichtig mit diesem Ansatz.
quelle
Je nachdem, wie Sie die Eigenschaft verwenden möchten, verwenden Sie am einfachsten einen optionalen Typ für Ihre Unterklasse und überschreiben die
didSet {}
Methode für die Super:Natürlich müssen Sie einige Zeit damit verbringen, zu überprüfen, ob die Klassen auf diese Weise initialisiert werden können. Wenn Sie jedoch die Eigenschaften auf optional setzen, schützen Sie sich vor Situationen, in denen das Casting nicht mehr funktioniert.
quelle
Sie können einfach eine andere Variable von RacingChassis erstellen.
quelle
chassis
und es uns ermöglicht, unsereRacingChassis
Instanz mit derchassis
Eigenschaft abzurufen / festzulegen.Versuche dies:
quelle
quelle
Im Folgenden kann ein einzelnes Objekt in Basis- und abgeleiteten Klassen verwendet werden. Verwenden Sie in der abgeleiteten Klasse die Eigenschaft für abgeleitete Objekte.
quelle
Eine leichte Variation anderer Antworten, aber einfacher und sicherer mit einigen netten Vorteilen.
Zu den Vorteilen gehört, dass es keine Einschränkung für das Chassis gibt (var, let, optional usw.) und es einfach ist, RaceCar in Unterklassen zu unterteilen. Unterklassen von RaceCar können dann ihren eigenen berechneten Wert für Chassis (oder RacingChassis) haben.
quelle
Legen Sie einfach eine neue imageview-Eigenschaft mit einer anderen Namenskonvention wie imgview fest, da imageView bereits eine eigene Eigenschaft ist und wir keine zwei starken Eigenschaften zuweisen können.
quelle