webentwicklung-frage-antwort-db.com.de

Überschreiben einer gespeicherten Eigenschaft in Swift

Mir ist aufgefallen, dass der Compiler mich eine gespeicherte Eigenschaft nicht mit einem anderen gespeicherten Wert überschreiben lässt (was ungerade erscheint):

class Jedi {
    var lightSaberColor = "Blue"
}


class Sith: Jedi {
    override var lightSaberColor = "Red" // Cannot override with a stored property lightSaberColor
}

Ich darf dies jedoch mit einer berechneten Eigenschaft machen:

class Jedi {
    let lightSaberColor = "Blue"
}


class Sith: Jedi {
    override var lightSaberColor : String{return "Red"}

}

Warum darf ich ihm keinen anderen Wert geben?

Warum ist das Überschreiben mit einer gespeicherten Eigenschaft ein Greuel und dies mit einem berechneten koscher? Was haben sie gedacht?

87
cfischer

Warum darf ich nicht einfach einen anderen Wert angeben?

Sie können einer geerbten Eigenschaft auf jeden Fall einen anderen Wert zuweisen. Sie können dies tun, wenn Sie die Eigenschaft in einem Konstruktor initialisieren, der diesen Anfangswert verwendet, und einen anderen Wert als die abgeleitete Klasse übergeben:

class Jedi {
    // I made lightSaberColor read-only; you can make it writable if you prefer.
    let lightSaberColor : String
    init(_ lsc : String = "Blue") {
        lightSaberColor = lsc;
    }
}

class Sith : Jedi {
    init() {
        super.init("Red")
    }
}

let j1 = Jedi()
let j2 = Sith()

println(j1.lightSaberColor)
println(j2.lightSaberColor)

Das Überschreiben einer Eigenschaft ist nicht gleichbedeutend mit einem neuen Wert. Es ist eher so, als würden Sie einer Klasse eine andere Eigenschaft zuweisen. Tatsächlich geschieht dies, wenn Sie eine berechnete Eigenschaft überschreiben: Der Code, der die Eigenschaft in der Basisklasse berechnet, lautet ersetzt durch Code, der die Überschreibung für diese Eigenschaft in der abgeleiteten Klasse berechnet.

Ist es möglich, die tatsächlich gespeicherte Eigenschaft zu überschreiben, d. H. lightSaberColor, die ein anderes Verhalten aufweist?

Abgesehen von Beobachtern haben gespeicherte Eigenschaften kein Verhalten, so dass wirklich nichts zu überschreiben ist. Durch den oben beschriebenen Mechanismus ist es möglich, der Eigenschaft einen anderen Wert zu geben. Dies tut genau das, was das Beispiel in der Frage mit einer anderen Syntax zu erreichen versucht.

52
dasblinkenlight

Für mich funktioniert Ihr Beispiel nicht in Swift 3.0.1.

In Spielplatz diesen Code eingegeben:

class Jedi {
    let lightsaberColor = "Blue"
}

class Sith: Jedi {
    override var lightsaberColor : String {
        return "Red"
    }
}

Fehler beim Kompilieren in Xcode:

kann nicht unveränderliche 'let' Eigenschaft 'lightsaberColor' mit dem Getter einer 'var' überschreiben

Nein, Sie können den Typ einer gespeicherten Eigenschaft nicht ändern. Das Liskov-Substitutionsprinzip zwingt Sie, die Verwendung einer Unterklasse an einem Ort zuzulassen, an dem die Oberklasse gewünscht wird.

Wenn Sie es jedoch in var ändern und daher die set zur berechneten Eigenschaft hinzufügen, können Sie die gespeicherte Eigenschaft mit einer berechneten Eigenschaft des gleichen Typs überschreiben.

class Jedi {
    var lightsaberColor = "Blue"
}


class Sith: Jedi {
    override var lightsaberColor : String {
        get {
            return "Red"
        }
        set {
            // nothing, because only red is allowed
        }
    }
}

Dies ist möglich, da es sinnvoll sein kann, von einer gespeicherten zu einer berechneten Eigenschaft zu wechseln.

Das Überschreiben einer gespeicherten var-Eigenschaft mit einer gespeicherten var-Eigenschaft ist jedoch nicht sinnvoll, da Sie den Wert der Eigenschaft nur ändern können.

Sie können eine gespeicherte Eigenschaft jedoch nicht mit einer gespeicherten Eigenschaft überschreiben.


Ich würde nicht sagen, dass Sith Jedi sind :-P. Daher ist es klar, dass dies nicht funktionieren kann.

36
Binarian

Sie möchten der Eigenschaft wahrscheinlich einen anderen Wert zuweisen:

class Jedi {
    var lightSaberColor = "Blue"
}


class Sith: Jedi {
    override init() {
        super.init()
        self.lightSaberColor = "Red"
    }
}
13
zisoft
class SomeClass {
    var hello = "hello"
}
class ChildClass: SomeClass {
    override var hello: String {
        set {
            super.hello = newValue
        }
        get {
            return super.hello
        }    
    }
}
9
Zhiping Yang

Für Swift 4 aus Apples Dokumentation :

Sie können eine geerbte Instanz oder Typeneigenschaft überschreiben, um .__ bereitzustellen. Ihren eigenen benutzerdefinierten Getter und Setter für diese Eigenschaft oder zum Hinzufügen von Eigenschaftsbeobachter, damit die überschreibende Eigenschaft beobachten kann, wann Der zugrunde liegende Eigenschaftswert ändert sich.

9
riyasavla

In Swift ist dies leider nicht möglich. Die beste Alternative ist folgende:

class Jedi {
    private(set) var lightsaberColor = "Blue"
}


class Sith: Jedi {
    override var lightsaberColor : String {
        get {
            return "Red"
        }
    }
}
2
Noah Wilder

Sie können auch eine Funktion zum Überschreiben verwenden. Es ist keine direkte Antwort, kann aber dieses Thema bereichern.

Klasse a 

override func viewDidLoad() {
    super.viewDidLoad()

    if shouldDoSmth() {
       // do
    }
}

public func shouldDoSmth() -> Bool {
    return true
}

Klasse B: A

public func shouldDoSmth() -> Bool {
    return false
}
0
Nik Kov

Ich hatte das gleiche Problem, eine Konstante für einen View-Controller festzulegen.

Da ich den Schnittstellen-Builder zum Verwalten der Ansicht verwende, kann ich init() nicht verwenden. Daher war die Problemumgehung ähnlich wie bei anderen Antworten, es sei denn, ich habe eine schreibgeschützte berechnete Variable für sowohl die Basisklasse als auch die vererbte Klasse verwendet.

class Jedi {
    var type: String {
        get { return "Blue" }
    }
}

class Sith: Jedi {
    override var type: String {
        get { return "Red" }
    }
}
0