Swift a une syntaxe de déclaration de propriété très similaire à C #:
var foo: Int {
get { return getFoo() }
set { setFoo(newValue) }
}
Cependant, il a aussi willSet
et didSet
actions. Ceux-ci sont appelés respectivement avant et après l'appel du setter. Quel est leur objectif, étant donné que vous pouvez simplement avoir le même code à l'intérieur du setter?
get
&set
) doit essentiellement avoir une propriété calculée sur la base d'une autre propriété, par exemple la conversion d'une étiquettetext
en une annéeInt
.didSet
&willSet
sont là pour dire ... hé cette valeur a été définie, maintenant faisons ceci par exemple Notre dataSource a été mise à jour ... alors rechargeons la tableView afin qu'elle inclue de nouvelles lignes. Pour un autre exemple, voir la réponse de dfri sur la façon d'appeler les déléguésdidSet
Réponses:
Le point semble être que, parfois, vous avez besoin d'une propriété qui a un stockage automatique et un certain comportement, par exemple pour notifier à d'autres objets que la propriété vient d'être modifiée. Lorsque tout ce que vous avez est
get
/set
, vous avez besoin d'un autre champ pour contenir la valeur. AvecwillSet
etdidSet
, vous pouvez agir lorsque la valeur est modifiée sans avoir besoin d'un autre champ. Par exemple, dans cet exemple:myProperty
imprime son ancienne et sa nouvelle valeur à chaque modification. Avec juste des getters et des setters, j'aurais besoin de ça à la place:Donc
willSet
etdidSet
représentent une économie de quelques lignes, et moins de bruit dans la liste des champs.la source
willSet
etdidSet
ne sont pas appelés lorsque vous définissez la propriété à partir d'une méthode init comme le note Apple:willSet and didSet observers are not called when a property is first initialized. They are only called when the property’s value is set outside of an initialization context.
myArrayProperty.removeAtIndex(myIndex)
... Pas prévu.Ma compréhension est que set et get sont pour les propriétés calculées (pas de support des propriétés stockées )
si vous venez d'un Objective-C sans oublier que les conventions de dénomination ont changé. Dans Swift, une variable iVar ou instance est nommée propriété stockée
Exemple 1 (propriété en lecture seule) - avec avertissement:
Cela se traduira par un avertissement car il en résulte un appel de fonction récursive (le getter appelle lui-même). L'avertissement dans ce cas est "Tentative de modification de" test "dans son propre getter".
Exemple 2. Lecture / écriture conditionnelle - avec avertissement
Problème similaire - vous ne pouvez pas le faire car il appelle récursivement le setter. Notez également que ce code ne se plaindra d'aucun initialiseur car il n'y a pas de propriété stockée à initialiser .
Exemple 3. Propriété calculée en lecture / écriture - avec magasin de sauvegarde
Voici un modèle qui permet le réglage conditionnel d'une propriété stockée réelle
Remarque Les données réelles sont appelées _test (bien qu'il puisse s'agir de n'importe quelle donnée ou combinaison de données) Notez également la nécessité de fournir une valeur initiale (vous devez également utiliser une méthode init) car _test est en fait une variable d'instance
Exemple 4. Utilisation de will et did set
Ici, nous verrons willSet et didSet intercepter un changement dans une propriété stockée réelle. Ceci est utile pour l'envoi de notifications, la synchronisation etc ... (voir exemple ci-dessous)
Exemple 5. Exemple concret - Conteneur ViewController
Notez l'utilisation des DEUX propriétés calculées et stockées. J'ai utilisé une propriété calculée pour éviter de définir deux fois la même valeur (pour éviter que de mauvaises choses ne se produisent!); J'ai utilisé willSet et didSet pour transmettre des notifications aux viewControllers (voir la documentation UIViewController et les informations sur les conteneurs viewController)
J'espère que cela aide, et je vous en prie, criez si j'ai fait une erreur ici!
la source
//I can't see a way to 'stop' the value being set to the same controller - hence the computed property
l'avertissement disparaît après que j'aie utilisé à laif let newViewController = _childVC {
place deif (_childVC) {
get
, je pense que vous devez ajouterif _childVC == nil { _childVC = something }
et ensuitereturn _childVC
.Ceux-ci sont appelés observateurs immobiliers :
Extrait de: Apple Inc. «The Swift Programming Language». iBooks. https://itun.es/ca/jEUH0.l
Je soupçonne que c'est pour permettre des choses que nous ferions traditionnellement avec KVO telles que la liaison de données avec des éléments d'interface utilisateur, ou le déclenchement d'effets secondaires du changement d'une propriété, le déclenchement d'un processus de synchronisation, le traitement en arrière-plan, etc., etc.
la source
la source
Vous pouvez également utiliser le
didSet
pour définir la variable sur une valeur différente. Cela ne provoque pas l'appel de l'observateur comme indiqué dans le guide des propriétés . Par exemple, il est utile lorsque vous souhaitez limiter la valeur comme ci-dessous:la source
Les nombreuses réponses existantes bien écrites couvrent bien la question, mais je mentionnerai, en détail, un ajout qui, je crois, mérite d'être couvert.
Les observateurs de propriétés
willSet
etdidSet
peuvent être utilisés pour appeler des délégués, par exemple, pour des propriétés de classe qui ne sont jamais mises à jour que par interaction de l'utilisateur, mais où vous voulez éviter d'appeler le délégué lors de l'initialisation de l'objet.Je citerai le commentaire voté par Klaas à la réponse acceptée:
Ceci est assez soigné car cela signifie par exemple que la
didSet
propriété est un bon choix de point de lancement pour les fonctions et rappels délégués, pour vos propres classes personnalisées.Par exemple, considérons un objet de contrôle utilisateur personnalisé, avec une propriété clé
value
(par exemple, la position dans le contrôle de notation), implémenté comme une sous-classe deUIView
:Après quoi, vos fonctions de délégué peuvent être utilisées dans, disons, certains contrôleurs de vue pour observer les changements clés dans le modèle
CustomViewController
, tout comme vous utiliseriez les fonctions de délégué inhérentesUITextFieldDelegate
auxUITextField
objets for (par exempletextFieldDidEndEditing(...)
).Pour cet exemple simple, utilisez un rappel délégué à partir
didSet
de la propriété de classevalue
pour indiquer à un contrôleur de vue que l'une de ses sorties a eu une mise à jour de modèle associée:Ici, la
value
propriété a été encapsulée, mais généralement: dans des situations comme celles-ci, veillez à ne pas mettre à jour lavalue
propriété de l'customUserControl
objet dans la portée de la fonction déléguée associée (ici:)didChangeValue()
dans le contrôleur de vue, ou vous vous retrouverez avec récursion infinie.la source
Et notez que cela
willSet
nécessite un nom de paramètre pour contourner, en revanche,didSet
ne le fait pas.la source
Getter et setter sont parfois trop lourds à implémenter juste pour observer les changements de valeur appropriés. Habituellement, cela nécessite une gestion supplémentaire des variables temporaires et des vérifications supplémentaires, et vous voudrez éviter même ce travail minime si vous écrivez des centaines de getters et setters. Ces trucs sont pour la situation.
la source
willSet
etdidSet
par rapport à un code setter équivalent? Cela semble être une affirmation audacieuse.Dans votre propre classe (de base),
willSet
etdidSet
sont assez redondants , car vous pouvez plutôt définir une propriété calculée (c'est-à-dire les méthodes get et set) qui accède à a_propertyVariable
et effectue les pré et post-évaluation souhaitées .Si, cependant , vous surchargez une classe où la propriété est déjà définie , alors les
willSet
etdidSet
sont utiles et non redondants!la source
Une chose
didSet
est vraiment pratique lorsque vous utilisez des prises pour ajouter une configuration supplémentaire.la source
Je ne connais pas C #, mais avec un peu de conjectures je pense que je comprends
Est-ce que. Cela ressemble beaucoup à ce que vous avez dans Swift, mais ce n'est pas la même chose: dans Swift, vous n'avez pas le
getFoo
etsetFoo
. Ce n'est pas une petite différence: cela signifie que vous n'avez pas de stockage sous-jacent pour votre valeur.Swift a stocké et calculé des propriétés.
Une propriété calculée a
get
et peut avoirset
(si elle est accessible en écriture). Mais le code dans le getter et le setter, s'il doit réellement stocker des données, doit le faire dans d' autres propriétés. Il n'y a pas de stockage de sauvegarde.Une propriété stockée, d'autre part, a un stockage de sauvegarde. Mais il ne pas avoir
get
etset
. Au lieu de cela, il awillSet
etdidSet
que vous pouvez utiliser pour observer les changements de variables et, éventuellement, déclencher des effets secondaires et / ou modifier la valeur stockée. Vous n'avez paswillSet
etdidSet
pour les propriétés calculées, et vous n'en avez pas besoin car pour les propriétés calculées, vous pouvez utiliser le code dansset
pour contrôler les modifications.la source
getFoo
etsetFoo
sont de simples espaces réservés pour tout ce que vous souhaitez que les getters et les setters fassent. C # n'en a pas besoin non plus. (J'ai manqué quelques subtilités syntaxiques comme je l'ai demandé avant d'avoir accès au compilateur.)