web-dev-qa-db-fra.com

Remplacer getter dans Swift

J'ai une situation où j'ai besoin de remplacer le getter d'une propriété.

Disons que nous avons:

public class MyBaseClass {
    private var _name: String
    public internal(set) var name: String {
        get {
            return self._name
        }
        set {
            self._name = newValue
        }
    }
}

Rien d'extraordinaire, je suppose.

Maintenant, si j'essaie de remplacer le getter dans une classe dérivée:

public class MyDerivedClass: MyBaseClass {
    public var name: String {
        get {
            return "Derived - \(super.name)"
        }
    }
}

J'obtiens l'erreur de compilation: Impossible de remplacer la propriété mutable par la propriété en lecture seule 'nom'.

Si j'essaie d'ajouter le setter et de le remplacer:

public class MyDerivedClass: MyBaseClass {
    public internal(set) var name: String {
        get {
            return "Derived - \(super.name)"
        }
        set {
            super.name = newValue
        }
    }
}

J'obtiens l'erreur: Le poseur de var de substitution doit être aussi accessible que la déclaration qu'il remplace.

Et si j'essaye ce qui suit:

public class MyDerivedClass: MyBaseClass {
    public internal(set) var name: String {
        get {
            return "Derived - \(super.name)"
        }
    }
}

Ensuite, le compilateur plante ...

Comment puis-je réussir à remplacer uniquement le getter?

27
BPCorp

Cela fonctionne pour moi:

    public class MyBaseClass {
        private var _name: String = "Hi"
        public internal(set) var name: String {
            get {
                return self._name
            }
            set {
                self._name = newValue
            }
        }
    }

    public class MyDerivedClass:MyBaseClass {
        override public var name: String {
            get {
                return "Derived - \(super.name)"
            }
            set {
                super._name = newValue
            }
        }
    }

    MyDerivedClass().name

MODIFIER

Ce code fonctionne pour moi dans une aire de jeux, en le plaçant dans le fichier Sources -> SupportCode.Swift

    public class MyBaseClass {
    private var _name: String = "Hi"
    public internal(set) var name: String {
        get {
            return self._name
        }
        set {
            self._name = newValue
        }
    }
    public init() {

    }

    }

    public class MyDerivedClass:MyBaseClass {
        override public var name: String {
            get {
                return "Derived - \(super.name)"
            }
            set {
               // do nothing
            }
        }
       public override init() {

        }
    }

C'est un peu un bodge car je reçois le même avertissement que vous que internal(set) ne peut pas être placé avant la variable de sous-classe surchargée. C'est peut-être un bug. Et aussi je triche pour m'assurer que le setter de la classe dérivée ne fait rien.

Une utilisation plus courante de internal(set) ou private(set) est d'avoir un code comme celui-ci, qui est similaire à celui de la documentation:

public class MyBaseClass {
    public private(set) var _name: String = "Hi"
    public var name: String {
        get {
            return self._name
        }
        set {
            self._name = newValue
        }
    }
    public init() {

    }

}

public class MyDerivedClass:MyBaseClass {
    override public var name: String {
        get {
            return "Derived - \(super.name)"
        }
        set {
           super._name = newValue
        }
    }
   public override init() {

    }
}

Ici, le setter peut être lu directement avec MyDerivedClass()._name mais il ne peut pas être modifié, par ex. cette MyDerivedClass()._name = "Fred" soulèverait une erreur mais MyDerivedClass().name = "Fred" serait OK.

25
sketchyTech

Problème 1

MyBaseClass ne compile pas car:

  1. il a une propriété stockée (_name)
  2. cette propriété stockée n'est pas facultative, elle ne peut donc pas être nulle
  3. il n'y a pas d'initialiseur pour le remplir

Donc, tout d'abord, nous devons ajouter un initialiseur approprié à MyBaseClass

public class MyBaseClass {
    private var _name: String
    public internal(set) var name: String {
        get { return self._name }
        set { self._name = newValue }
    }
    init(name : String){
        _name = name
    }
}

Problème 2

Maintenant, nous pouvons déclarer MyDerivedClass qui remplace la propriété calculée:

  1. nous devons utiliser le mot-clé magique override
  2. nous devons fournir à la fois le setter et le getter

Voici le code:

public class MyDerivedClass: MyBaseClass {
    public override var name: String {
        get { return "Derived - \(super.name)" }
        set { super.name = newValue }
    }
}

Tester

De mon terrain de jeu:

let somethingWithAName = MyDerivedClass(name: "default name")
println(somethingWithAName.name) // > "Derived - default name"
somethingWithAName.name = "another name"
println(somethingWithAName.name) // > "Derived - another name"
6
Luca Angeletti