Dans la session 403 de la WWDC 2014 Intermediate Swift et transcription , il y avait la diapositive suivante
L'orateur a dit que dans ce cas, si nous ne l'utilisons pas [unowned self]
, ce sera une fuite de mémoire. Cela signifie-t-il que nous devrions toujours utiliser la [unowned self]
fermeture intérieure?
Sur la ligne 64 de ViewController.swift de l'application Swift Weather , je n'utilise pas [unowned self]
. Mais je mets à jour l'interface utilisateur en utilisant certains @IBOutlet
s comme self.temperature
et self.loadingIndicator
. Cela peut être OK car tous les @IBOutlet
s que j'ai définis le sont weak
. Mais pour la sécurité, devrions-nous toujours utiliser [unowned self]
?
class TempNotifier {
var onChange: (Int) -> Void = {_ in }
var currentTemp = 72
init() {
onChange = { [unowned self] temp in
self.currentTemp = temp
}
}
}
swift
automatic-ref-counting
Jake Lin
la source
la source
onChange
devrait être une[weak self]
fermeture, car c'est une propriété publique (en interne, mais quand même), donc un autre objet pourrait obtenir et stocker la fermeture, en gardant l'objet TempNotifier autour (indéfiniment si l'objet utilisateur n'a pas lâché laonChange
fermeture jusqu'à ce qu'il voit leTempNotifier
disparu, via sa propre référence faible à laTempNotifier
) . Sivar onChange …
c'était le cas ,private var onChange …
ce[unowned self]
serait correct. Je n'en suis cependant pas sûr à 100%; quelqu'un me corrige s'il vous plaît si je me trompe.[]
? Je ne trouve pas l'explication dans les documents Apple.{}
est la fermeture vide (l'instance de la fermeture) par défaut (ne fait rien),(Int) -> Void
est la définition de la fermeture.Réponses:
Non, il y a certainement des moments où vous ne voudriez pas utiliser
[unowned self]
. Parfois, vous voulez que la fermeture se capture elle-même afin de s'assurer qu'elle est toujours là au moment où la fermeture est appelée.Exemple: effectuer une demande de réseau asynchrone
Si vous faites une demande de réseau asynchrone , vous ne voulez la fermeture de retenir
self
pour quand la demande se termine. Cet objet peut avoir été autrement désalloué, mais vous voulez toujours pouvoir gérer la fin de la demande.Quand utiliser
unowned self
ouweak self
La seule fois où vous voulez vraiment utiliser
[unowned self]
ou[weak self]
c'est quand vous créez un cycle de référence solide . Un solide cycle de référence est lorsqu'il y a une boucle de propriété où les objets finissent par se posséder (peut-être par le biais d'un tiers) et donc ils ne seront jamais désalloués car ils s'assurent tous les deux de rester ensemble.Dans le cas spécifique d'une fermeture, il vous suffit de réaliser que toute variable référencée à l'intérieur de celle-ci est "détenue" par la fermeture. Tant que la fermeture est autour, ces objets sont garantis autour. La seule façon d'arrêter cette propriété est de faire le
[unowned self]
ou[weak self]
. Donc, si une classe possède une fermeture et que cette fermeture capture une référence forte à cette classe, alors vous avez un cycle de référence solide entre la fermeture et la classe. Cela inclut également si la classe possède quelque chose qui possède la fermeture.Plus précisément dans l'exemple de la vidéo
Dans l'exemple de la diapositive,
TempNotifier
possède la fermeture via laonChange
variable membre. Si elles ne déclarentself
queunowned
la fermeture aurait aussi propreself
création d' un cycle de référence forte.Différence entre
unowned
etweak
La différence entre
unowned
etweak
est celle quiweak
est déclarée comme étant facultative alors que ceunowned
n'est pas le cas. En le déclarant,weak
vous pouvez gérer le cas où il pourrait être nul à l'intérieur de la fermeture à un moment donné. Si vous essayez d'accéder à uneunowned
variable qui se trouve être nulle, cela bloquera tout le programme. Donc, utilisez uniquementunowned
lorsque vous êtes certain que la variable sera toujours présente pendant la fermeture.la source
[weak self]
dans une demande de réseau asynchrone se trouve dans un contrôleur de vue où cette demande est utilisée pour remplir la vue. Si l'utilisateur se retire, nous n'avons plus besoin de remplir la vue, ni de référence au contrôleur de vue.weak
les références sont également définiesnil
lorsque l'objet est désalloué.unowned
les références ne le sont pas.unowned
est utilisé pendantnon-Optional
queweak
est utilisé pourOptional
notreself
estOptional
ounon-optional
?Mise à jour 11/2016
J'ai écrit un article sur cette extension de cette réponse (en examinant SIL pour comprendre ce que fait ARC), consultez-le ici .
Réponse originale
Les réponses précédentes ne donnent pas vraiment de règles simples sur le moment de les utiliser et pourquoi, alors permettez-moi d'ajouter quelques choses.
La discussion non possédée ou faible se résume à une question de durée de vie de la variable et de la fermeture qui y fait référence.
Scénarios
Vous pouvez avoir deux scénarios possibles:
La fermeture a la même durée de vie de la variable, donc la fermeture ne sera accessible que jusqu'à ce que la variable soit accessible . La variable et la fermeture ont la même durée de vie. Dans ce cas, vous devez déclarer la référence comme non possédée . Un exemple courant est celui
[unowned self]
utilisé dans de nombreux exemples de petites fermetures qui font quelque chose dans le contexte de leurs parents et qui ne sont référencés nulle part ailleurs ne survivent pas à leurs parents.La durée de vie de fermeture est indépendante de celle de la variable, la fermeture peut toujours être référencée lorsque la variable n'est plus joignable. Dans ce cas, vous devez déclarer la référence faible et vérifier qu'elle n'est pas nulle avant de l'utiliser (ne forcez pas le déballage). Un exemple courant de ceci est le que
[weak delegate]
vous pouvez voir dans certains exemples de fermeture référençant un objet délégué complètement indépendant (sur la durée de vie).Utilisation réelle
Alors, lequel utiliserez-vous / devriez-vous utiliser la plupart du temps?
Citant Joe Groff de Twitter :
Vous trouverez plus d'informations sur
*
le fonctionnement interne sans propriétaire ici .*
Habituellement également appelé non propriétaire (sûr) pour indiquer que les vérifications d'exécution (qui conduisent à un crash pour les références non valides) sont effectuées avant d'accéder à la référence non possédée.la source
J'ai pensé ajouter des exemples concrets spécifiquement pour un contrôleur de vue. De nombreuses explications, pas seulement ici sur Stack Overflow, sont vraiment bonnes, mais je travaille mieux avec des exemples réels (@drewag a pris un bon départ à ce sujet):
weak
, car elle a une longue durée de vie. Le contrôleur de vue peut se fermer avant la fin de la demande, ilself
ne pointe donc plus vers un objet valide lorsque la fermeture est appelée.Si vous avez une fermeture qui gère un événement sur un bouton. Cela peut être
unowned
dû au fait que dès que le contrôleur de vue disparaît, le bouton et tous les autres éléments auxquels il peut faire référenceself
disparaissent en même temps. Le bloc de fermeture disparaîtra également en même temps.la source
weak
plutôt queunowned
non?Si le self peut être nul dans la fermeture, utilisez [self faible] .
Si l' auto ne sera jamais nul dans la fermeture, utilisez [auto sans propriétaire] .
La documentation Apple Swift contient une grande section avec des images expliquant la différence entre l'utilisation de fermetures fortes , faibles et sans propriétaire :
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html
la source
Voici des citations brillantes des forums de développeurs Apple qui décrivent de délicieux détails:
unowned
vsunowned(safe)
vsunowned(unsafe)
unowned
contreweak
Mise à jour: Dans Swift moderne
weak
utilise en interne le même mécanisme queunowned
fait . Cette comparaison est donc incorrecte car elle compare Objective-Cweak
avec Swiftunonwed
.Les raisons
Excité, hein?
la source
Il y a d'excellentes réponses ici. Mais les récents changements apportés à la façon dont Swift implémente les références faibles devraient changer le moi faible de chacun contre les décisions d'utilisation de soi sans propriétaire. Auparavant, si vous aviez besoin des meilleures performances, utiliser le soi sans propriétaire était supérieur au soi faible, tant que vous pouviez être certain que le soi ne serait jamais nul, car accéder au soi sans propriétaire est beaucoup plus rapide que d'accéder au soi faible.
Mais Mike Ash a documenté comment Swift a mis à jour l'implémentation de vars faibles pour utiliser les tables d'appoint et comment cela améliore considérablement les faibles performances personnelles.
https://mikeash.com/pyblog/friday-qa-2017-09-22-swift-4-weak-references.html
Maintenant qu'il n'y a pas de pénalité de performance importante pour un soi faible, je pense que nous devrions par défaut l'utiliser à l'avenir. L'avantage du self faible est qu'il est facultatif, ce qui facilite l'écriture de code plus correct, c'est essentiellement la raison pour laquelle Swift est un si bon langage. Vous pensez peut-être que vous savez quelles situations sont sûres pour l'utilisation de soi sans propriétaire, mais mon expérience en examinant beaucoup de code d'autres développeurs est, la plupart ne le savent pas. J'ai corrigé de nombreux plantages où le self sans propriétaire était désalloué, généralement dans des situations où un thread d'arrière-plan se termine après la désallocation d'un contrôleur.
Les bogues et les plantages sont les parties de programmation les plus chronophages, douloureuses et coûteuses. Faites de votre mieux pour écrire le code correct et évitez-les. Je recommande de faire une règle de ne jamais forcer les options de déballage et de ne jamais utiliser le soi sans propriétaire au lieu du soi faible. Vous ne perdrez rien en manquant les moments où le déballage forcé et le soi sans propriétaire sont en fait sûrs. Mais vous gagnerez beaucoup en éliminant les plantages et les bogues difficiles à trouver et à déboguer.
la source
weak
ne peut pas être utilisé à la place d'ununowned
?Selon Apple-doc
Exemple -
la source
Si rien de ce qui précède n'a de sens:
tl; dr
Explication:
J'ai récupéré ce qui suit ci-dessous à: faible lien sans propriétaire . D'après ce que j'ai rassemblé, le moi sans propriétaire ne peut pas être nul, mais le moi faible peut l'être, et le moi sans propriétaire peut conduire à des pointeurs pendants ... quelque chose d'infâme dans Objective-C. J'espère que cela aide
Les références non possédées, comme les références faibles, n'augmentent pas le nombre de rétentions de l'objet référé. Cependant, dans Swift, une référence non possédée a l' avantage supplémentaire de ne pas être facultative . Cela les rend plus faciles à gérer plutôt que d'avoir recours à la liaison facultative. Ce n'est pas différent des options implicitement non emballées. De plus, les références non possédées ne sont pas à zéro . Cela signifie que lorsque l'objet est désalloué, il ne remet pas à zéro le pointeur. Cela signifie que l'utilisation de références non possédées peut, dans certains cas, conduire à des pointeurs pendants. Pour les nerds qui se souviennent de l'époque d'Objective-C comme moi, les références non possédées sont mappées aux références unsafe_unretained.
C'est là que ça devient un peu déroutant.
Ils peuvent tous deux être utilisés pour briser les cycles de rétention. Alors, quand les utilisons-nous?!
Selon les documents d' Apple :
la source
la source