web-dev-qa-db-fra.com

Quelle est la différence entre une référence faible et une référence non possédée?

Swift a:

  • Références fortes
  • Références faibles
  • Références non possédées

En quoi une référence non possédée est-elle différente d'une référence faible?

Quand est-il prudent d'utiliser une référence non possédée?

Les références non possédées constituent-elles un risque pour la sécurité comme pointeurs en suspens en C/C++?

227
Ian Ringrose

Les références weak et unowned ne créent pas de maintien strong sur l'objet référencé (elles n'augmentent pas le nombre de rétentions afin d'empêcher ARC de libérer l'emplacement de l'objet référencé).

Mais pourquoi deux mots-clés? Cette distinction est liée au fait que les types Optional sont intégrés au langage Swift. Longue histoire à leur sujet: types facultatifs offre la sécurité de la mémoire (cela fonctionne à merveille avec règles du constructeur de Swift - qui sont strictes afin de fournir cet avantage).

Une référence weak permet de devenir nil (cela se produit automatiquement lorsque l'objet référencé est désalloué). Par conséquent, le type de votre propriété doit être facultatif - vous êtes donc obligé en tant que programmeur pour le vérifier avant de l’utiliser (le compilateur vous oblige autant que possible à écrire du code sécurisé).

Une référence unowned suppose qu'elle ne deviendra jamais nil au cours de sa vie. Une référence non possédée doit être définie lors de l'initialisation - cela signifie que la référence sera définie comme un type non facultatif pouvant être utilisé en toute sécurité sans vérification. Si, d'une manière ou d'une autre, l'objet référencé est désalloué, l'application se bloque lorsque la référence non possédée est utilisée.

De la documentation Apple :

Utilisez une référence faible chaque fois que cela est valide pour que cette référence devienne nulle à un moment donné de son existence. Inversement, utilisez une référence non possédée lorsque vous savez que la référence ne sera jamais nulle une fois définie lors de l'initialisation.

La documentation contient des exemples traitant des cycles de conservation et de leur rupture. Tous ces exemples sont extraits de the docs .

Exemple pour le mot clé weak:

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
}

class Apartment {
    let number: Int
    init(number: Int) { self.number = number }
    weak var tenant: Person?
}

Et maintenant, pour certains ASCII art (vous devriez aller voir la documentation - ils ont de jolis diagrammes):

Person ===(strong)==> Apartment
Person <==(weak)===== Apartment

Les exemples Person et Apartment illustrent une situation dans laquelle deux propriétés, dont les deux sont autorisées à être nulles, peuvent générer un cycle de référence puissant. Ce scénario est mieux résolu avec une référence faible. Les deux entités peuvent exister sans dépendance stricte l'une par rapport à l'autre.

Exemple pour le mot clé unowned:

class Customer {
    let name: String
    var card: CreditCard?
    init(name: String) { self.name = name }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer
    init(number: UInt64, customer: Customer) { self.number = number; self.customer = customer }
}

Dans cet exemple, une Customer peut avoir ou non une CreditCard, mais une CreditCard sera toujours toujours associé à un Customer. Pour représenter cela, la classe Customer a une propriété facultative card, mais la classe CreditCard a une propriété non optionnelle (et non possédée) customer.

Customer ===(strong)==> CreditCard
Customer <==(unowned)== CreditCard

L'exemple Customer et CreditCard montre une situation dans laquelle une propriété autorisée à être nulle et une autre propriété ne pouvant pas l'être ont le potentiel de générer un cycle de référence fort. Ce scénario est mieux résolu avec une référence non propriétaire.

Note d'Apple:

Les références faibles doivent être déclarées en tant que variables, pour indiquer que leur valeur peut changer à l'exécution. Une référence faible ne peut pas être déclarée comme constante.

Il existe également un troisième scénario dans lequel les deux propriétés devraient toujours avoir une valeur et aucune propriété ne devrait jamais être nulle une fois l'initialisation terminée.

Et il existe également les scénarios classiques du cycle de conservation à éviter lorsque vous travaillez avec des fermetures.

Pour cela, je vous encourage à visiter le documentation Apple , ou à lire le livre .

335
Ilea Cristian

Q1. En quoi une "référence non possédée" est-elle différente d'une "référence faible"?

Référence faible:

Une référence faible est une référence qui ne maintient pas un contrôle fort sur l'instance à laquelle elle fait référence et n'empêche donc pas ARC de supprimer l'instance référencée. Étant donné que les références faibles ne peuvent avoir "aucune valeur", vous devez déclarer chaque référence faible comme ayant un type facultatif. (Apple Docs)

Référence non possédée:

A l'instar des références faibles, une référence non possédée ne conserve pas une emprise forte sur l'instance à laquelle elle fait référence. Contrairement à une référence faible, cependant, une référence non possédée est supposée avoir toujours une valeur. De ce fait, une référence non possédée est toujours définie comme un type non facultatif. (Apple Docs)

Quand utiliser chacun:

Utilisez une référence faible chaque fois que cela est valide pour que cette référence devienne nulle à un moment donné de son existence. Inversement, utilisez une référence non possédée lorsque vous savez que la référence ne sera jamais nulle une fois définie lors de l'initialisation. (Apple Docs)


Q2. Quand est-il prudent d'utiliser une "référence non possédée"?

Comme cité ci-dessus, une référence non possédée est supposée avoir toujours une valeur. Vous ne devriez donc l'utiliser que lorsque vous êtes sûr que la référence ne sera jamais nulle. Apple Les documents illustrent un scénario d'utilisation pour les références non possédées à l'aide de l'exemple suivant.

Supposons que nous ayons deux classes Customer et CreditCard. Un client peut exister sans carte de crédit, mais une carte de crédit n’existera pas sans client, c’est-à-dire qu’on peut supposer qu’une carte de crédit aura toujours un client. Donc, ils devraient avoir la relation suivante:

class Customer {
    var card: CreditCard?
}

class CreditCard {
    unowned let customer: Customer
}

Q3. Les "références non possédées" font-elles référence à un risque de sécurité tel que les "pointeurs en suspens" en C/C++

Je ne pense pas.

Étant donné que les références non possédées ne sont que des références faibles dont la valeur est garantie, il ne devrait en aucun cas être un risque pour la sécurité. Toutefois, si vous essayez d'accéder à une référence non possédée après la désallocation de l'instance à laquelle elle fait référence, vous déclencherez une erreur d'exécution et l'application se bloquera.

C'est le seul risque que je vois avec ça.

Lien vers Apple Docs

27
Myxtic

Si self peut être nul dans l'utilisation de la fermeture, utilisez [moi faible] .

Si self ne sera jamais nul dans l'utilisation de la fermeture, utilisez [moi non possédé] .

Si cela se bloque lorsque vous utilisez [moi non possédé] , alors self est probablement nul à un moment donné de cette fermeture et vous devrez probablement utiliser [moi faible] à la place.

Découvrez les exemples d'utilisation fort , faible et non possédée dans les fermetures:

https://developer.Apple.com/library/ios/documentation/Swift/conceptual/Swift_programming_language/AutomaticReferenceCounting.html

25
TenaciousJay

Extraits de lien

Quelques points de conclusion

  • Pour déterminer si vous avez même besoin de vous inquiéter de la force, de la faiblesse ou de l'absence de propriétaire, demandez: "Est-ce que je traite de types de référence". Si vous travaillez avec Structs ou Enums, ARC ne gère pas la mémoire de ces types et vous n'avez même pas à vous soucier de la spécification de faible ou non propriétaire pour ces constantes ou variables.
  • Les références fortes conviennent parfaitement aux relations hiérarchiques où le parent fait référence à l'enfant, mais pas l'inverse. En fait, les références fortes sont le type de référence le plus approprié, la plupart du temps.
  • Lorsque deux instances sont éventuellement liées l'une à l'autre, assurez-vous que l'une de ces instances contient une référence faible à l'autre.
  • Lorsque deux instances sont liées de telle sorte qu’une des instances ne peut pas exister sans l’autre, l’instance avec la dépendance obligatoire doit contenir une référence non possédée à l’autre instance.
4
Abhinav Singh

Les références non possédées sont une sorte de référence faible utilisée dans le cas d'une relation de la même durée de vie entre deux objets, lorsqu'un objet ne doit jamais appartenir qu'à un autre objet. C'est un moyen de créer une liaison immuable entre un objet et l'une de ses propriétés.

Dans l'exemple donné dans la vidéo intermédiaire Swift WWDC, une personne possède une carte de crédit et une carte de crédit ne peut avoir qu'un seul détenteur. Sur la carte de crédit, la personne ne doit pas être une propriété facultative, car vous ne voulez pas avoir une carte de crédit flottante avec un seul propriétaire. Vous pouvez rompre ce cycle en faisant de la propriété du titulaire du crédit une référence faible, mais vous devez également la rendre facultative et variable (par opposition à constante). La référence non propriétaire dans ce cas signifie que même si CreditCard n’a pas de participation dans une personne, sa vie en dépend.

class Person {
    var card: CreditCard?
}

class CreditCard {

    unowned let holder: Person

    init (holder: Person) {
        self.holder = holder
    }
}
0
JuJoDi

ARC

ARC est une fonctionnalité de compilation qui constitue la version d'Apple de la gestion automatisée de la mémoire. Il représente le comptage automatique des références. Cela signifie que cela seulement libère de la mémoire pour les objets quand il y a zéro fort leurs références.

FORT

C'est essentiellement une référence normale (pointeur et tout), mais c'est spécial en ce sens qu'elle protège l'objet référé d'être désalloué par ARC en augmentant il conserve le compte par 1. En substance, tant que rien a une forte référence à un objet, il ne sera pas désalloué.

En règle générale, nous pouvons utiliser des références fortes lorsque les relations hiérarchiques des objets sont linéaires . Lorsqu'une hiérarchie de références fortes circule de parent à enfant, il est toujours correct d'utiliser des références fortes.

Résolution des cycles de référence puissants entre les instances de classe

Les emplacements importants à utiliser weak et unowned sont des variables lorsque vous avez des cycles de conservation potentiels. Un cycle de conservation correspond à ce qui se produit lorsque deux objets sont fortement référencés. Si 2 objets sont fortement référencés, ARC ne générera pas le code de message de libération approprié sur chaque instance car ils se maintiennent en vie.

FAIBLE

Une référence faible est simplement un pointeur sur un objet qui ne protège pas la suppression de la désaffectation de l'objet par ARC. Alors que les références fortes augmentent le nombre de rétention d'un objet de 1, les références faibles ne le font pas . De plus, les références faibles remettent à zéro le pointeur sur votre objet lorsqu'il désalloue avec succès. Cela garantit que lorsque vous accédez à une référence faible, il s'agira soit d'un objet valide, soit de nil.

ARC définit automatiquement une référence faible sur nil lorsque l'instance à laquelle il fait référence est désallouée. Et, comme les références faibles doivent permettre la modification de leur valeur en nil au moment de l'exécution, elles sont toujours déclarées comme variables

Utiliser

Dans une situation où deux propriétés, qui sont toutes deux autorisées à être nil. Ce scénario est mieux résolu avec une référence weak.

Utilisez une référence weak lorsque l'autre instance a une durée de vie plus courte , c'est-à-dire lorsque l'autre instance peut être désallouée en premier.

SANS PROPRIÉTAIRE

Les références non possédées, comme les références faibles, n'augmentent pas le nombre de retenues de l'objet référencé. Les références non possédées ne sont pas à zéro. Cela signifie que lorsque l'objet est désalloué, il ne met pas le pointeur à zéro. Cela signifie que l'utilisation de références non propriétaires peut, dans certains cas, conduire à pointeurs en suspens .

ARC ne définit jamais la valeur nil d'une référence non possédée, ce qui signifie que les références non possédées sont définies à l'aide de types non facultatifs .


IMPORTANT.

Utilisez une référence non possédée uniquement lorsque vous êtes sûr que la référence fait toujours référence à une instance qui n'a pas été désallouée.

Si vous essayez d'accéder à la valeur d'une référence non possédée après la désallocation de cette instance, vous obtiendrez une erreur d'exécution - Attempted to read an unowned reference but object was already deallocated


REMARQUE

Swift fournit également des références non propriétaires non sécurisées dans les cas où vous devez désactiver les vérifications de sécurité de l'exécution, par exemple pour des raisons de performances. Comme pour toutes les opérations dangereuses, vous prenez la responsabilité de vérifier ce code pour la sécurité.

Vous indiquez une référence non propriétaire non sécurisée en écrivant unowned(unsafe). Si vous essayez d'accéder à une référence non propriétaire non sécurisée après la désallocation de l'instance à laquelle elle fait référence, votre programme essaiera d'accéder à l'emplacement de la mémoire où se trouvait l'instance, ce qui constitue une opération non sécurisée.

Utiliser

Dans une situation où une propriété qui est autorisée à être nil et une autre propriété qui ne peut pas être nil. Ce scénario est mieux résolu avec une référence unowned.

Utilisez une référence unowned lorsque l'autre instance a la durée de vie identique ou un plus long à vie. Tout comme un implicitement non emballé , si vous pouvez garantir que la référence ( ne sera pas être nil à son point d'utilisation, utilisez unowned. Sinon, vous devriez utiliser weak.

Recommande fortement de lire un doc et un source

0
yoAlex5