Avec cette classe simple, je reçois le compilateur warning
Tentative de modification/d’accès à
x
dans son propre setter/getter
et quand je l'utilise comme ça:
var p: point = Point()
p.x = 12
Je reçois un EXC_BAD_ACCESS. Comment puis-je faire cela sans soutenir explicitement les ivars?
class Point {
var x: Int {
set {
x = newValue * 2 //Error
}
get {
return x / 2 //Error
}
}
// ...
}
Les Setters et Getters s’appliquent à computed properties
; ces propriétés n'ont pas de stockage dans l'instance - la valeur du getter doit être calculée à partir d'autres propriétés d'instance. Dans votre cas, il n'y a pas de x
à attribuer.
Explicitement: "Comment puis-je faire cela sans sauvegarder explicitement ivars". Vous ne pouvez pas - vous aurez besoin de quelque chose pour sauvegarder la propriété calculée. Essaye ça:
class Point {
private var _x: Int = 0 // _x -> backingX
var x: Int {
set { _x = 2 * newValue }
get { return _x / 2 }
}
}
Plus précisément, dans le REPL de Swift:
15> var pt = Point()
pt: Point = {
_x = 0
}
16> pt.x = 10
17> pt
$R3: Point = {
_x = 20
}
18> pt.x
$R4: Int = 10
Les Setters/Getters à Swift sont assez différents d’ObjC. La propriété devient une propriété calculée, ce qui signifie que non possède une variable de support telle que _x
comme dans ObjC.
Dans le code de solution ci-dessous, vous pouvez voir que xTimesTwo
fait pas rien stocker, mais simplement calcule le résultat de x
.
Voir Documents officiels sur les propriétés calculées .
La fonctionnalité souhaitée peut également être Observateurs de propriétés .
Ce dont vous avez besoin c'est:
var x:Int
var xTimesTwo:Int {
set {
x = newValue / 2
}
get {
return x * 2
}
}
Vous pouvez modifier d'autres propriétés dans le setter/getters, ce à quoi elles sont destinées.
Vous pouvez personnaliser la valeur définie à l'aide de la propriété observateur. Pour ce faire, utilisez 'didSet' au lieu de 'set'.
class Point {
var x:Int {
didSet {
x = x * 2
}
}
...
Quant à getter ...
class Point {
var doubleX: Int {
get {
return x / 2
}
}
...
Pour élaborer sur la réponse de GoZoner:
Votre vrai problème ici est que vous appelez votre getter de manière récursive.
var x:Int
{
set
{
x = newValue * 2 // This isn't a problem
}
get {
return x / 2 // Here is your real issue, you are recursively calling
// your x property's getter
}
}
Comme le commentaire de code le suggère ci-dessus, vous appelez infiniment le getter de la propriété x, qui continuera à s'exécuter jusqu'à ce que vous obteniez un code EXC_BAD_ACCESS (vous pouvez voir le disque dans l'angle inférieur droit de l'environnement de jeu de votre Xcode).
Prenons l'exemple de la documentation Swift :
struct Point {
var x = 0.0, y = 0.0
}
struct Size {
var width = 0.0, height = 0.0
}
struct AlternativeRect {
var Origin = Point()
var size = Size()
var center: Point {
get {
let centerX = Origin.x + (size.width / 2)
let centerY = Origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set {
Origin.x = newValue.x - (size.width / 2)
Origin.y = newValue.y - (size.height / 2)
}
}
}
Notez que la propriété center computed ne se modifie jamais ni ne se retourne dans la déclaration de la variable.
Afin de remplacer les variables setter
et getter
pour les variables Swift, utilisez le code ci-dessous
var temX : Int?
var x: Int?{
set(newX){
temX = newX
}
get{
return temX
}
}
Nous devons conserver la valeur de variable dans une variable temporaire, car essayer d'accéder à la même variable dont le getter/setter est surchargé entraînera des boucles infinies.
Nous pouvons invoquer le passeur simplement comme ceci
x = 10
Getter sera invoqué au tir en dessous de la ligne de code
var newVar = x
Vous êtes récursivement en définissant x
avec x
. Comme si quelqu'un te demandait quel âge as-tu? Et vous répondez "j'ai deux fois mon âge". Ce qui n'a pas de sens.
Vous devez dire que j'ai deux fois l'âge de John ou toute autre variable mais vous-même.
les variables calculées dépendent toujours d'une autre variable.
La règle générale est never accéder à la propriété elle-même depuis entre le getter, c'est-à-dire get
. Parce que cela déclencherait une autre get
qui en déclencherait une autre. . . Ne l'imprimez même pas. Parce que l’impression nécessite aussi d’obtenir la valeur avant de pouvoir l’imprimer!
struct Person{
var name: String{
get{
print(name) // DON'T do this!!!!
return "as"
}
set{
}
}
}
let p1 = Person()
Comme cela donnerait l'avertissement suivant:
Tenter d'accéder à 'nom' à partir de son propre getter.
L'erreur semble vague comme ceci:
Au lieu de cela, vous pouvez utiliser didSet
. Avec didSet
, vous obtiendrez une valeur identique à celle qui avait été définie auparavant. Pour plus voir cette réponse .
Dans la classe ci-dessous, le setter et le getter sont appliqués à la variable sideLength
class Triangle: {
var sideLength: Double = 0.0
init(sideLength: Double, name: String) { //initializer method
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 3
}
var perimeter: Double {
get { // getter
return 3.0 * sideLength
}
set { //setter
sideLength = newValue / 4.0
}
}
var triangle = Triangle(sideLength: 3.9, name: "a triangle")
print(triangle.perimeter) // invoking getter
triangle.perimeter = 9.9 // invoking setter
Essayez d'utiliser ceci:
var x:Int!
var xTimesTwo:Int {
get {
return x * 2
}
set {
x = newValue / 2
}
}
Ceci est fondamentalement la réponse de Jack Wu, mais la différence est que, dans la réponse de Jack Wu, sa variable x est var x: Int
, dans le mien, ma variable x est comme ceci: var x: Int!
;
Mise à jour pour Swift 5.1
À partir de Swift 5.1, vous pouvez maintenant obtenir votre variable sans utiliser le mot clé get. Par exemple:
var helloWorld: String {
"Hello World"
}
Les setters et getters de Swift s’appliquent aux propriétés/variables calculées. Ces propriétés/variables ne sont pas réellement stockées en mémoire, mais calculées en fonction de la valeur des propriétés/variables stockées.
Consultez la documentation Swift d’Apple sur le sujet: Déclarations de variables Swift .
Voici une réponse théorique. Cela peut être trouvé ici
Une propriété {get set} ne peut pas être une propriété stockée constante. Ce doit être une propriété calculée et les deux méthodes get et set doivent être implémentées.