J'ai remarqué que le compilateur ne me laissera pas remplacer une propriété stockée par une autre valeur stockée (ce qui semble étrange):
class Jedi {
var lightSaberColor = "Blue"
}
class Sith: Jedi {
override var lightSaberColor = "Red" // Cannot override with a stored property lightSaberColor
}
Cependant, je suis autorisé à le faire avec une propriété calculée:
class Jedi {
let lightSaberColor = "Blue"
}
class Sith: Jedi {
override var lightSaberColor : String{return "Red"}
}
Pourquoi ne suis-je pas autorisé à lui donner une autre valeur?
Pourquoi remplacer avec une propriété stockée une abomination et le faire avec une casher calculée? À quoi pensaient-ils?
Pourquoi ne suis-je pas autorisé à lui donner une autre valeur?
Vous êtes définitivement autorisé à attribuer une valeur différente à une propriété héritée. Vous pouvez le faire si vous initialisez la propriété dans un constructeur qui prend cette valeur initiale et transmettez une valeur différente de la classe dérivée:
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)
Remplacer une propriété, ce n’est pas la même chose que de lui donner une nouvelle valeur, c’est plus comme donner à une classe une propriété différente. En fait, c'est ce qui se produit lorsque vous substituez une propriété calculée: le code qui calcule la propriété dans la classe de base est replacement / par un code qui calcule le remplacement de cette propriété dans la classe dérivée.
[Est-il] possible de remplacer la propriété stockée réelle, c'est-à-dire
lightSaberColor
qui a un autre comportement?
Hormis les observateurs, les propriétés stockées n'ont pas de comportement, il n'y a donc rien à remplacer. Donner à la propriété une valeur différente est possible grâce au mécanisme décrit ci-dessus. Cela correspond exactement à ce que l'exemple de la question tente de réaliser, avec une syntaxe différente.
Pour moi, votre exemple ne fonctionne pas dans Swift 3.0.1.
Entré dans la cour de récréation ce code:
class Jedi {
let lightsaberColor = "Blue"
}
class Sith: Jedi {
override var lightsaberColor : String {
return "Red"
}
}
Lance une erreur lors de la compilation dans Xcode:
ne peut pas remplacer la propriété immuable 'let', 'lightsaberColor', avec le getter d'un 'var'
Non, vous ne pouvez pas changer le type d'une propriété stockée. Le principe de substitution de Liskov oblige à autoriser l'utilisation d'une sous-classe dans un endroit où la super-classe est souhaitée.
Mais si vous le changez en var
et ajoutez donc set
dans la propriété calculée, vous pouvez remplacer la propriété stockée par une propriété calculée du même type.
class Jedi {
var lightsaberColor = "Blue"
}
class Sith: Jedi {
override var lightsaberColor : String {
get {
return "Red"
}
set {
// nothing, because only red is allowed
}
}
}
Cela est possible car il peut être judicieux de passer d'une propriété stockée à une propriété calculée.
Mais remplacer une propriété var
stockée par une propriété var
stockée n’a aucun sens, car vous ne pouvez changer que la valeur de la propriété.
Cependant, vous ne pouvez pas remplacer une propriété stockée par une propriété stockée.
Je ne dirais pas que les Sith sont Jedi :-P. Par conséquent, il est clair que cela ne peut pas fonctionner.
Vous voulez probablement attribuer une autre valeur à la propriété:
class Jedi {
var lightSaberColor = "Blue"
}
class Sith: Jedi {
override init() {
super.init()
self.lightSaberColor = "Red"
}
}
class SomeClass {
var hello = "hello"
}
class ChildClass: SomeClass {
override var hello: String {
set {
super.hello = newValue
}
get {
return super.hello
}
}
}
Pour Swift 4, à partir de documentation Apple :
Vous pouvez remplacer une instance héritée ou une propriété de type pour fournir votre propre getter et setter personnalisé pour cette propriété, ou pour ajouter observateurs de propriété pour permettre à la propriété dominante d’observer quand la valeur de la propriété sous-jacente change.
Dans Swift, ce n'est malheureusement pas possible. La meilleure alternative est la suivante:
class Jedi {
private(set) var lightsaberColor = "Blue"
}
class Sith: Jedi {
override var lightsaberColor : String {
get {
return "Red"
}
}
}
Vous pouvez également utiliser une fonction pour remplacer. Ce n'est pas une réponse directe, mais peut enrichir ce sujet)
Classe A
override func viewDidLoad() {
super.viewDidLoad()
if shouldDoSmth() {
// do
}
}
public func shouldDoSmth() -> Bool {
return true
}
Classe B: A
public func shouldDoSmth() -> Bool {
return false
}
J'ai eu le même problème pour définir une constante pour un contrôleur de vue.
Comme j'utilise un générateur d'interface pour gérer la vue, je ne peux pas utiliser init()
; ma solution de contournement était donc similaire à d'autres réponses, à la différence que j'utilisais une variable calculée en lecture seule dans les classes de base et héritées.
class Jedi {
var type: String {
get { return "Blue" }
}
}
class Sith: Jedi {
override var type: String {
get { return "Red" }
}
}