2
votes

Quand la méthode modify d'une propriété calculée est-elle appelée et que fait-elle?

Considérez la définition de classe suivante

class Class1 {
    var property: String {
        get {
            return ""
        }
        set {
            print("set called")
        }
    }
}

Si vous ajoutez un point d'arrêt dans le bloc get et que vous lisez la propriété , l'exécution est suspendue et vous observez que la méthode la plus élevée dans la pile d'appels est Class1.property.getter

De même, si vous ajoutez un point d'arrêt à l'intérieur du bloc d'ensemble et définissez la propriété , l'exécution est suspendue et vous observez que la méthode la plus élevée dans la pile d'appels est Class1.property.setter

Lors du débogage d'un crash, j'ai observé que la méthode la plus élevée dans la pile d'appels était ClassName. computedPropertyName.modify ClassName et computedPropertyName sont des espaces réservés.

Quelqu'un peut-il indiquer ce que la méthode modifie fait et quand il est appelé?


2 commentaires

Obtenez-vous le plantage dans la propriété ?


Le code présent dans la question est uniquement à des fins d'illustration. J'ai observé un crash dans une application que j'ai écrite. Quand j'ai observé la pile d'appels au moment du crash, j'ai vu que le haut de la pile était la méthode modify d'une propriété calculée qui avait un getter et un setter


3 Réponses :


0
votes

modify est appelé chaque fois que vous modifiez la valeur de la propriété. Donc, pour une chaîne, ce serait à chaque fois que vous définissez, mettez à jour ou supprimez la valeur de ladite chaîne.

Ce qui suit serait un exemple de quand modify est appelé.

var string: String? //modify not called here 
string = “new string”
string = nil


0 commentaires

0
votes
  • morceaux de code qui seront appelés à chaque fois que vous les attribuerez.
  • Les propriétés calculées sont toujours des variables
  • get {} : lors de la récupération de la valeur d'une propriété, ce bloc de code sera exécuté.

    set {} : lors de la définition de valeur d'une propriété cette partie du code sera exécutée.

    Exemple

    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(newCenter) {
            origin.x = newCenter.x - (size.width / 2)
            origin.y = newCenter.y - (size.height / 2)
        }
    }
    

    Document de propriété Swift


0 commentaires

3
votes

Comme get et set , modify est un accesseur. Cela fait partie de l'évolution vers les accesseurs généralisés a >, et est utilisé pour obtenir une référence mutable à une valeur sous-jacente à l'aide d'une coroutine yield-once.

Vous pouvez en fait écrire des accesseurs modify dans Swift d'aujourd'hui en utilisant _modify mot-clé. Cependant, notez que ce n'est pas encore une fonctionnalité officielle, donc tout code qui dépend explicitement de _modify et yield est sujet à rupture sans préavis.

class C {
  var property = "hello" {
    // What the compiler synthesises:
    _modify {
      yield &property
    }
  }
}

class D : C {
  override var property: String {
    get { return "goodbye" }
    set { print(newValue) }
    // What the compiler synthesises:
    _modify {
      var tmp = property.get()
      yield &tmp
      property.set(tmp)
    }
  }
}

func mutateProperty(_ c: C) {
  c.property += "foo"
}

Lors de la mutation de c.property , l'accesseur _modify est appelé pour obtenir une référence mutable à un stockage sous-jacent. Le mot-clé yield est utilisé pour transférer le contrôle vers l'appelant avec une référence au stockage de _property . À ce stade, l'appelant peut appliquer des mutations arbitraires au stockage, dans ce cas en appelant + = . Une fois la mutation terminée, le contrôle est retransféré vers _modify , auquel point il revient.

Pourquoi l'accesseur modify est-il utile? H3 >

En termes simples, cela évite la copie de valeurs, ce qui peut déclencher des opérations de copie coûteuses pour les types de copie sur écriture tels que String , Array et Dictionnaire (je parle de ce plus en détail ici a >). La mutation de c.property via un accesseur modify permet à la chaîne d'être mutée sur place, plutôt que de muter une copie temporaire qui est ensuite réécrite.

Pourquoi modify utilise-t-il des coroutines?

L'utilisation d'une coroutine permet de rendre temporairement une référence mutable à l'appelant, après quoi l'accesseur peut alors exécuter une logique supplémentaire.

Par exemple:

class Class1 {
  var property: String {
    get {
      return ""
    }
    set {
      print("set called")
    }
    // What the compiler synthesises:
    _modify {
      var tmp = property.get() // Made up syntax.
      yield &tmp
      property.set(tmp)
    }
  }
}

qui laisse d'abord l'appelant effectuer ses mutations, puis ajoute "world!" à la fin de la chaîne.

Pourquoi l'accesseur modify apparaît-il dans votre code?

Le compilateur Swift peut synthétiser implicitement un code modify > accesseur pour les propriétés mutables. Pour une propriété calculée avec un getter et un setter, l'implémentation ressemble à ceci:

class C {
  var _property: String = ""
  var property: String {
    get {
      return _property
    }
    _modify {
      yield &_property
      _property += " world!"
    }
  }
}

let c = C()
c.property += "hello"
print(c.property) // hello world!

Le getter est d'abord appelé afin d'obtenir une copie mutable de la valeur, une référence à cette copie mutable est ensuite renvoyée à l'appelant, puis le setter est appelé avec la nouvelle valeur.

L'accesseur modify est principalement utilisé dans ce cas afin d'activer efficace mutation d'une propriété par envoi dynamique. Prenons l'exemple suivant:

class C {
  var _property: String = ""
  var property: String {
    get {
      return _property
    }
    _modify {
      yield &_property
    }
  }
}

let c = C()
c.property += "hello"
print(c.property) // hello

Lors de la mutation de c.property , l'accesseur modify est distribué dynamiquement à. S'il s'agit d'une instance de C , cela permet à une référence au stockage de la propriété d'être directement renvoyée à l'appelant, permettant une mutation sur place efficace. S'il s'agit d'une instance de D , alors l'appel de modify a juste le même effet que l'appel du getter suivi du setter.

Pourquoi modifier apparaît comme l'appel le plus élevé dans la trace de pile de votre crash?

Je suppose que c'est parce que le compilateur a intégré l'implémentation de votre getter et setter dans le modifiez l'accesseur , ce qui signifie que le plantage a probablement été causé par l'implémentation du getter ou du setter de votre propriété.


0 commentaires